Canvas提供了一个方法 drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,int colorffset,Paint paint)

这个方法可以对bitmap进行扭曲 参数说明如下:

1.bitmap     需要扭曲的源位图

2.meshWidth   控制在横向上把该源位图划成成多少格,为0时不绘制图像。

3.meshHeight   控制在纵向上把该源位图划成成多少格,为0时不绘制图像。

4.verts      verts是个一维数组,保存所有顶点坐标信息。偶数项保存x坐标,奇数项保存y坐标。比如有有meshWidthmeshHeight个网格, 如果vertOffset为0,那么算上两端就有(meshWidth+1)(meshHeight+1)个顶点,verts数组就应该至少长度为(meshWidth+1)*(meshHeight+1)。

5.vertOffset 控制verts数组中从第几个数组元素开始才对bitmap进行扭曲

6.Colors 可以为空,不为空为每个顶点定义对应的颜色值,至少需要有(meshWidth+1) * (meshHeight+1) * 2 + meshOffset 个(x,y)坐标。

7.colorOffset colors数组中开始跳过的(x,y)对的数目。

8.paint 可以为空

Mesh代表的是网格,这个东西的原理就是按照网格来重新拉伸你的图像,假想在一张图片上有很多网格,如下图。

在这张图上,每一条横线和纵线有一个焦点,我们可以控制这些焦点的位置来重新改变图片的形状和画面,也就是网格怎么扭动, 图像就会怎么动。比如把焦点位置改变成下面这样,图像就跟着扭曲了。

在DrawBitmapMesh中,只需要定义好这个顶点将要扭曲到哪个坐标点上,然后将顶点扭曲后的坐标告诉DrawBitmapMesh,便会自动计算出周边的线条扭曲形式,并根据结果扭曲图像。

总结上面的,需要做的就是三步: 1、根据图片,生成原始的、四四方方的网格 2、根据上面生成的网格,算出将要扭曲的网格 3、将网格传入drawBitmapMesh

下面用前面的知识做一个自定义view,让view实现像旗帜飘动的效果,效果图如下:

view代码如下:

public class MeshView extends View{
	private int WIDTH = 200 ;
	private int HEIGHT = 200 ;
	private int count = (WIDTH + 1) * (HEIGHT + 1) ;
	private float[] verts = new float[count * 2] ;
	private float[] orig = new float[count * 2] ;
	private Bitmap mBitmap;
	private float K ;
	public MeshView(Context context){
			super(context);
			initView() ;
	}
	public MeshView(Context context,AttributeSet attrs){
		super(context,attrs);
		initView() ;
}
	private void initView(){
		int index  = 0  ;
		mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.screenshot);
		float bmWidth = mBitmap.getWidth() ;
		float bmHeight = mBitmap.getHeight() ;
		for(int i = 0 ; i < HEIGHT + 1; i++){
			float fy = bmHeight * i / HEIGHT ;
			for(int j = 0 ; j < WIDTH + 1 ; j ++ ){
				float fx = bmWidth * j / WIDTH ;
				orig[index * 2 + 0 ] = verts[index * 2 + 0 ] = fx ;
				orig[index * 2 + 1 ] = verts[index * 2 + 1 ] = fy ;
				index += 1 ;
			}
		}
	}
	@Override
	protected void onDraw(Canvas canvas){
		for(int i = 0 ; i < HEIGHT + 1; i++){
			for(int j = 0 ; j < WIDTH + 1 ; j ++ ){
				verts[(i*(WIDTH+1) + j ) * 2 + 0 ] += 0 ;
				float offsetY  = (float) Math.sin( (float)j / WIDTH * 2 * Math.PI + K * 2 * Math.PI) ;
				verts[(i*(WIDTH+1) + j ) * 2 + 1 ]  = orig[(i*(WIDTH+1) + j ) * 2 + 1 ] +
						offsetY * 50 ;
			}
		}
		K += 0.1F ;
		canvas.drawBitmapMesh(mBitmap, WIDTH, HEIGHT, verts, 0, null, 0, null) ;
		invalidate() ;
	}
}