以下是摘自Android群英传(徐宜生编)
</pre></h1><pre style="margin-top: 0px; margin-bottom: 16px; widows: auto; overflow: auto; font-family: 'Meiryo UI', 'YaHei Consolas Hybrid', Consolas, 'Malgun Gothic', 'Segoe UI', 'Trebuchet MS', Helvetica, monospace, monospace; padding: 16px; line-height: 1.45; word-break: break-all; word-wrap: normal; color: rgb(51, 51, 51); border: 0px; background: transparent;"><pre name="code" class="java">public class XfermodeView extends View{
private Bitmap mBgBitmap , mFgBitmap ;
private Paint mPaint ;
private Canvas mCanvas ;
private Path mPath ;
public XfermodeView(Context context , AttributeSet attrs ){
super(context , attrs );
init();
}
private void init(){
mPaint = new Paint() ;
mPaint.setAlpha(0) ; //关键
mPaint.setXfermode( new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setWidth(50);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPath = new Path();
mBgBitmap = BitmapFactory.decodeResource(getResource() , R.drawable.test);
mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth() , mBgBitmap.getHeigth() , Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mFgBitmap);
mCanvas.drawColor(Color.GRAY);
}
@Override
public boolean onTouchEvent(MotionEvent event){
switch(event.getAction()){
case MotionEvent.ACTION_DOWN :
mPath.reset();
mPath.moveTo(event.getX() , event.getY());
break;
case MotionEvent.ACTION_MOVE :
mPath.lineTo(event.getX() , event.getY());
break;
}
mCanvas.drawPath(mPath , mPaint);
invalidate();
return true ;
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(mBgBitmap, 0 , 0 , null);
canvas.drawBitmao(mFgBitmap, 0 , 0 , null);
}
}
下面着重分析demo中的方法调用顺序:
第一,XfermodeView()构造器
第二,然后init(),在这个方法中,设置了mPaint的属性,生成了两个同样大小的bitmap-------mBgBitmap 和灰色的 mFgBitmap ,注意mCanvas 操作的是mFgBitmap这个位图
第三,系统调用onDraw,注意这里的Canvas与mCanvas不同,这里的Canvas操作的是一个新的位图,两次的drawBitmap调用依次将mBgBitmap 和 灰色的mFgBitmap 覆盖在新的位图上,所以一开始生成界面的时候看到就是灰色的一个样子。
第四,当用户手指在界面上移动,就会触发onTouchEvent,这时候 ,mCanvas.drawPath继续操作mFgBitmap,由于mPaint的属性是DST_IN,所以mFgBitmap现在剩下Path形状的透明块;然后调用invadalite
第五,invalidate会使得系统调用onDraw,所以canvas会将mBgBitmap和透明Path状的mFgBitmap覆盖在新位图上,最终实现刮刮卡的效果。
</pre></h1><pre style="margin-top: 0px; margin-bottom: 16px; widows: auto; overflow: auto; font-family: 'Meiryo UI', 'YaHei Consolas Hybrid', Consolas, 'Malgun Gothic', 'Segoe UI', 'Trebuchet MS', Helvetica, monospace, monospace; padding: 16px; line-height: 1.45; word-break: break-all; word-wrap: normal; color: rgb(51, 51, 51); border: 0px; background: transparent;"><pre name="code" class="java">public class XfermodeView extends View{
private Bitmap mBgBitmap , mFgBitmap ;
private Paint mPaint ;
private Canvas mCanvas ;
private Path mPath ;
public XfermodeView(Context context , AttributeSet attrs ){
super(context , attrs );
init();
}
private void init(){
mPaint = new Paint() ;
mPaint.setAlpha(0) ; //关键
mPaint.setXfermode( new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setWidth(50);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPath = new Path();
mBgBitmap = BitmapFactory.decodeResource(getResource() , R.drawable.test);
mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth() , mBgBitmap.getHeigth() , Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mFgBitmap);
mCanvas.drawColor(Color.GRAY);
}
@Override
public boolean onTouchEvent(MotionEvent event){
switch(event.getAction()){
case MotionEvent.ACTION_DOWN :
mPath.reset();
mPath.moveTo(event.getX() , event.getY());
break;
case MotionEvent.ACTION_MOVE :
mPath.lineTo(event.getX() , event.getY());
break;
}
mCanvas.drawPath(mPath , mPaint);
invalidate();
return true ;
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(mBgBitmap, 0 , 0 , null);
canvas.drawBitmao(mFgBitmap, 0 , 0 , null);
}
}