为了实现动画效果,使用drawBitmapMess方法对图像进行扭曲,使用定时器以100毫秒的频率按圆形轨迹扭曲图像。
扭曲的关键是生成verts数组。本例一开始会先生成verts数组的初始值:有一定水平和垂直间距的网点坐标。然后通过warp方法按一定的数学方法变化verts数组中的坐标。关键部分的代码如下:
定义基本变量:MyView是用于显示扭曲的图像的自定义view,angle是圆形轨迹的当前角度:
privatestaticBitmap bitmap;
privateMyView myView;
privateintangle =0; // 圆形轨迹当前的角度
privateHandler handler =newHandler()
{
publicvoidhandleMessage(Message msg)
{
switch(msg.what)
{
case1:
Random random =newRandom();
// 计算图形中心点坐标
intcenterX = bitmap.getWidth() /2;
intcenterY = bitmap.getHeight() /2;
doubleradian = Math.toRadians((double) angle);
// 通过圆心坐标、半径和当前角度计算当前圆周的某点横坐标
intcurrentX = (int) (centerX +100* Math.cos(radian));
// 通过圆心坐标、半径和当前角度计算当前圆周的某点纵坐标
intcurrentY = (int) (centerY +100* Math.sin(radian));
// 重绘View,并在圆周的某一点扭曲图像
myView.mess(currentX, currentY);
angle +=2;
if(angle >360)
angle =0;
break;
}
super.handleMessage(msg);
}
};
privateTimerTask timerTask =newTimerTask()
{
publicvoidrun()
{
Message message =newMessage();
message.what =1;
handler.sendMessage(message);
}
以下是自定义view,MyView的具体内容:
privatestaticclassMyViewextendsView
{
privatestaticfinalint;
privatestaticfinalint;
privatestaticfinalintCOUNT = (WIDTH +1) * (HEIGHT +1);
privatefinalfloat[] verts =newfloat[COUNT *2];
privatefinalfloat[] orig =newfloat[COUNT *2];
privatefinalMatrix matrix =newMatrix();
privatefinalMatrix m =newMatrix();
// 设置verts数组的值
privatestaticvoidsetXY(float[] array,intindex,floatx,floaty)
{
array[index *2+0] = x;
array[index *2+1] = y;
}
publicMyView(Context context)
{
super(context);
setFocusable(true);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
floatw = bitmap.getWidth();
floath = bitmap.getHeight();
intindex =0;
// 生成verts和orig数组的初始值,这两个数组的值是一样的,只是在扭曲的过程中需要修改verts
// 的值,而修改verts的值要将原始的值保留在orig数组中
for(inty =0; y <= HEIGHT; y++)
{
floatfy = h * y / HEIGHT;
for(intx =0; x <= WIDTH; x++)
{
floatfx = w * x / WIDTH;
setXY(verts, index, fx, fy);
setXY(orig, index, fx, fy);
index +=1;
}
}
matrix.setTranslate(10,10);
setBackgroundColor(Color.WHITE);
}
@Override
protectedvoidonDraw(Canvas canvas)
{
canvas.concat(matrix);
canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts,0,null,0,null);
}
// 用于扭曲图像的方法,在该方法中根据当前扭曲的点(扭曲区域的中心点),也就是cx和cy参数,
// 来不断变化verts数组中的坐标值
privatevoidwarp(floatcx,floatcy)
{
finalfloatK =100000; // 该值越大,扭曲得越严重(扭曲的范围越大)
float[] src = orig;
float[] dst = verts;
// 按一定的数学规则生成verts数组中的元素值
for(inti =0; i < COUNT *2; i +=2)
{
floatx = src[i +0];
floaty = src[i +1];
floatdx = cx - x;
floatdy = cy - y;
floatdd = dx * dx + dy * dy;
floatd = FloatMath.sqrt(dd);
floatpull = K / ((float) (dd *d));
if(pull >=1)
{
dst[i +0] = cx;
dst[i +1] = cy;
}
else
{
dst[i +0] = x + dx * pull;
dst[i +1] = y + dy * pull;
}
}
}
// 用于MyView外部控制图像扭曲的方法。该方法在handleMessage方法中被调用
publicvoidmess(intx,inty)
{
float[] pt ={ x, y };
m.mapPoints(pt);
// 重新生成verts数组的值
warp(pt[0], pt[1]);
invalidate();
}
}
}
以下是Activity的onCreate方法:
protectedvoidonCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
myView =newMyView(this);
setContentView(myView);
Timer timer =newTimer();
// 开始定时器
timer.schedule(timerTask,0,100);
}
下面来看看扭曲后的效果,不同时刻,图片呈现出不同的扭曲效果: