双缓冲机制其实很简单,就是通过一个内存中的bitmap将绘画轨迹记录下来,然后再绘制到view上面。
下面的例子来自于《疯狂Android讲义》,简单易懂,这本书很适合初学者.
public class DrawView extends View {
float preX;
float preY;
private Path path;
public Paint paint = null;
final int VIEW_WIDTH = 900;
final int VIEW_HEIGHT = 1024;
//定义一个内存中的图片, 该图片将作为缓冲区
Bitmap cacheBitmap = null;
//定义cacheBitmap上的Canvas对象
Canvas cacheCanvas = null;
public DrawView(Context context, AttributeSet set){
super(context, set);
//创建一个与该view相同大小的缓冲区
cacheBitmap = Bitmap.createBitmap(VIEW_WIDTH, VIEW_HEIGHT, Bitmap.Config.ARGB_8888);
cacheCanvas = new Canvas();
path = new Path();
//设置cacheCanvas将会绘制到内存中的cacheBitmap上
cacheCanvas.setBitmap(cacheBitmap);
paint = new Paint(Paint.DITHER_FLAG);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setAntiAlias(true);
paint.setDither(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y);
preX = x;
preY = y;
break;
case MotionEvent.ACTION_MOVE:
path.quadTo(preX, preY, x, y);
preX = x ;
preY = y;
break;
case MotionEvent.ACTION_UP:
cacheCanvas.drawPath(path, paint);
path.reset();
break;
}
// Log.i("ysong", "调用了invalidate()函数");
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
Paint bmpPaint = new Paint();
//将cacheBitmap绘制到该View组件上
canvas.drawBitmap(cacheBitmap, 0, 0, bmpPaint);
//沿着path绘制
canvas.drawPath(path, paint);
//为什么还要绘制一次path???
//这行代码非常重要,
//每次手指在屏幕上面移动,path会将轨迹记录下来,然后绘制到缓冲的bitmap上面
// view 每次调用invalidate()更新的时候,会将bitmap上面缓冲的内容绘制到view上面(也就是canvas)
// ACTION_MOVE 和 ACTION_DOWN 也会触发invalid()更新view,这个时候path的内容还没有绘制到cacheBitmap上面,
// 如果没有上面这行canvas.drawPath(path, paint), 效果就会是当手指离开屏幕时,之前绘制的轨迹才会出现,感觉像是慢了半拍
// 有了上面这一行代码,当ACTION_MOVE手指移动的时候,就会把临时的path绘制到view上面,这样感觉像是画笔随着手指在动
// 最后再把cacheBitmap的内容绘制到view上面
//ACTION_MOVE 其实并不是从手指DOWN到UP的过程,其中会触发很多次invalid()函数,
// ACTION_MOVE其实包含了两个动作,只不是期间的时间间隔非常短, 看起来感觉像是一个动作, 可以通过log来测试一下,看一下移动调用了多少次invalidate()
}
}