前段時(shí)間,產(chǎn)品有個(gè)需求就是要搞一個(gè)抽獎(jiǎng)活動(dòng),類似支付寶的刮刮卡功能.自然想到了Paint的Xfermode.話不多說,先上效果.
在Paint的使用中,有一個(gè)方法叫做setXfermode,這個(gè)方法需要傳遞一個(gè)Xfermode的實(shí)例,為了實(shí)現(xiàn)這個(gè)效果,我們使用PorterDuffXfermode中的SRC_OUT模式,先上代碼再講原理.
首先,準(zhǔn)備好兩張圖片,一張是底圖,這個(gè)是不變的 也就是最下面那張圖.一張是源圖,也就是最上層那張圖.
還是老套路,自定義控件繼承自View,在構(gòu)造方法中先初始化畫筆Paint,準(zhǔn)備好底圖以及源圖,還有一張跟源圖相同大小的透明圖片,初始化Path.
public GuaguaCard(Context context, AttributeSet attrs) {
????super(context, attrs);
????mBitPaint=newPaint();
????mBitPaint.setColor(Color.BLACK);
????mBitPaint.setStyle(Paint.Style.STROKE);
????mBitPaint.setStrokeWidth(45);
????BmpText=BitmapFactory.decodeResource(getResources(),R.drawable.guaguaka_text1,n????ull);
????BmpSRC= BitmapFactory.decodeResource(getResources(),R.drawable.guaguaka,null);
????BmpDST= Bitmap.createBitmap(BmpSRC.getWidth(),BmpSRC.getHeight(), ????Bitmap.Config.ARGB_8888);
????mPath=newPath();
}
在onDraw方法中先將BmpText繪制到畫布上.創(chuàng)建一個(gè)新圖層,然后根據(jù)將手指的移動(dòng)軌跡繪制到BmpDST上,將BmpDST繪制到畫布上,最后將BmpSRC以PorterDuff.Mode.SRC_OUT的模式繪制到canvas上.這樣底層圖片BmpText永遠(yuǎn)都在最下面的圖層,然后BmpDST與BmpSRC的混合結(jié)果將鋪在上面.這樣就可以達(dá)到我們想要的結(jié)果.
上代碼:
@Override
protected void onDraw(Canvas canvas) {
????super.onDraw(canvas);
????canvas.drawBitmap(BmpText,0,0,mBitPaint);
????//官方叫法離屏緩存
????intlayerId = canvas.saveLayer(0,0, getWidth(), getHeight(),null, ? ?????Canvas.ALL_SAVE_FLAG);
????//將path繪制到dst圖像上
????Canvas canvas1 =newCanvas(BmpDST);
????canvas1.drawPath(mPath,mBitPaint);
????//然后把目標(biāo)圖像畫到畫布上
????canvas.drawBitmap(BmpDST,0,0,mBitPaint);
????//使用Xfermode繪制源圖
????mBitPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
????canvas.drawBitmap(BmpSRC,0,0,mBitPaint);
????// 還原混合模式
????mBitPaint.setXfermode(null);
????// 還原畫布
????canvas.restoreToCount(layerId);
? ?}
@Override
public boolean onTouchEvent(MotionEvent event) {
????switch(event.getAction()){
????case MotionEvent.ACTION_DOWN:
????mPath.moveTo(event.getX(),event.getY());
????mPreX= event.getX();
????mPreY= event.getY();
????return true;
????case MotionEvent.ACTION_MOVE:
????float endX = (mPreX+event.getX())/2;
????float endY = (mPreY+event.getY())/2;
????mPath.quadTo(mPreX,mPreY,endX,endY);
????mPreX= event.getX();
????mPreY=event.getY();
????break;
????case MotionEvent.ACTION_UP:
????break;
}
????postInvalidate();
????return super.onTouchEvent(event);
}
這里面有一個(gè)特別重要的方法就是mBitPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT))
根據(jù)PorterDuff的模式不同,展現(xiàn)的效果也不同.SRC_OUT的效果就是按照源圖片BmpSRC以及目標(biāo)圖片BmpDST的進(jìn)行組合,最終來繪制源圖片.那這個(gè)組合的方式我們來看一下源碼:
/** [Sa * (1 - Da), Sc * (1 - Da)] */
也就是根據(jù)上面的規(guī)則對(duì)源圖片以及目標(biāo)圖片的顏色ARGB通道來進(jìn)行組合,當(dāng)我手勢(shì)滑動(dòng)的時(shí)候目標(biāo)圖片的對(duì)應(yīng)區(qū)域的alpha值就變成1了,所以對(duì)應(yīng)的區(qū)域就透明了,其他區(qū)域時(shí)透明的所以對(duì)應(yīng)區(qū)域就按源圖展示,這樣就實(shí)現(xiàn)了刮刮卡效果了,是不是很神奇!