Android绘画之扭曲图像
16lz
2021-01-26
(转载于:http://blog.ophonesdn.com/mobileguy)
本例使用drawBitmapMess方法对图像进行扭曲。为了实现动画效果,本例中使用定时器以100毫秒的频率按圆形轨迹扭曲图像。下面先看看扭曲后的效果,图1和图2是不同位置扭曲后的效果。
图1
图2
扭曲的关键是生成verts数组。本例一开始会先生成verts数组的初始值:有一定水平和垂直间距的网点坐标。然后通过warp方法按一定的数学方法变化verts数组中的坐标。本例的完整代码如下:
001package net.blogjava.mobile;002 003 import java.util.Random;004 import java.util.Timer;005 import java.util.TimerTask;006 import android.app.Activity;007 import android.content.Context;008 import android.graphics.Bitmap;009 import android.graphics.BitmapFactory;010 import android.graphics.Canvas;011 import android.graphics.Color;012 import android.graphics.Matrix;013 import android.os.Bundle;014 import android.os.Handler;015 import android.os.Message;016 import android.util.FloatMath;017 import android.util.Log;018 import android.view.View;019 020 public class Main extends Activity021 {022 private static Bitmap bitmap;023 private MyView myView;024 private int angle = 0; // 圆形轨迹当前的角度025 private Handler handler = new Handler()026 {027 public void handleMessage(Message msg)028 {029 switch (msg.what)030 {031 case 1:032 Random random = new Random();033 // 计算图形中心点坐标034 int centerX = bitmap.getWidth() / 2;035 int centerY = bitmap.getHeight() / 2;036 double radian = Math.toRadians((double) angle);037 // 通过圆心坐标、半径和当前角度计算当前圆周的某点横坐标038 int currentX = (int) (centerX + 100 * Math.cos(radian));039 // 通过圆心坐标、半径和当前角度计算当前圆周的某点纵坐标040 int currentY = (int) (centerY + 100 * Math.sin(radian));041 // 重绘View,并在圆周的某一点扭曲图像042 myView.mess(currentX, currentY);043 angle += 2;044 if (angle > 360)045 angle = 0;046 break;047 }048 super.handleMessage(msg);049 }050 };051 private TimerTask timerTask = new TimerTask()052 {053 public void run()054 {055 Message message = new Message();056 message.what = 1;057 handler.sendMessage(message);058 }059 };060 @Override061 protected void onCreate(Bundle savedInstanceState)062 {063 super.onCreate(savedInstanceState);064 myView = new MyView(this);065 setContentView(myView); 066 Timer timer = new Timer();067 // 开始定时器068 timer.schedule(timerTask, 0, 100);069 }070 // 用于显示扭曲的图像071 private static class MyView extends View072 {073 private static final int WIDTH = 20;074 private static final int HEIGHT = 20;075 private static final int COUNT = (WIDTH + 1) * (HEIGHT + 1);076 private final float[] verts = new float[COUNT * 2];077 private final float[] orig = new float[COUNT * 2];078 private final Matrix matrix = new Matrix();079 private final Matrix m = new Matrix();080 // 设置verts数组的值081 private static void setXY(float[] array, int index, float x, float y)082 {083 array[index * 2 + 0] = x;084 array[index * 2 + 1] = y;085 }086 public MyView(Context context)087 {088 super(context);089 setFocusable(true);090 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);091 float w = bitmap.getWidth();092 float h = bitmap.getHeight();093 int index = 0;094 // 生成verts和orig数组的初始值,这两个数组的值是一样的,只是在扭曲的过程中需要修改verts095 // 的值,而修改verts的值要将原始的值保留在orig数组中096 for (int y = 0; y <= HEIGHT; y++)097 {098 float fy = h * y / HEIGHT;099 for (int x = 0; x <= WIDTH; x++)100 {101 float fx = w * x / WIDTH;102 setXY(verts, index, fx, fy);103 setXY(orig, index, fx, fy);104 index += 1;105 }106 }107 matrix.setTranslate(10, 10);108 setBackgroundColor(Color.WHITE);109 }110 @Override111 protected void onDraw(Canvas canvas)112 {113 canvas.concat(matrix);114 canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts, 0, null, 0,null);115 }116 // 用于扭曲图像的方法,在该方法中根据当前扭曲的点(扭曲区域的中心点),也就是cx和cy参数,117 // 来不断变化verts数组中的坐标值118 private void warp(float cx, float cy)119 {120 final float K = 100000; // 该值越大,扭曲得越严重(扭曲的范围越大)121 float[] src = orig;122 float[] dst = verts;123 // 按一定的数学规则生成verts数组中的元素值124 for (int i = 0; i < COUNT * 2; i += 2)125 {126 float x = src[i + 0];127 float y = src[i + 1];128 float dx = cx - x;129 float dy = cy - y;130 float dd = dx * dx + dy * dy;131 float d = FloatMath.sqrt(dd);132 float pull = K / ((float) (dd *d));133 if (pull >= 1)134 {135 dst[i + 0] = cx;136 dst[i + 1] = cy;137 }138 else139 {140 dst[i + 0] = x + dx * pull;141 dst[i + 1] = y + dy * pull;142 }143 }144 }145 // 用于MyView外部控制图像扭曲的方法。该方法在handleMessage方法中被调用146 public void mess(int x, int y)147 {148 float[] pt ={ x, y };149 m.mapPoints(pt);150 // 重新生成verts数组的值151 warp(pt[0], pt[1]);152 invalidate();153 }154 }155 }
更多相关文章
- Android打电话过程
- Android---把数据保存到数据库中(一)
- cocos2d怎么设置屏幕朝向?横屏 or 竖屏设置
- Android(安卓)API Demos学习(4) - Receive Result
- [置顶] 【Android】 给我一个Path,还你一个酷炫动画
- Matrix源码分析之第一篇
- Android精简小笔记(2):广播机制
- 4 行代码实现 ANDROID 快速文件下载
- 研究Android事件分发笔记