前段時間,產品有個需求就是要搞一個抽獎活動,類似支付寶的刮刮卡功能.自然想到了Paint的Xfermode.話不多說,先上效果.
在Paint的使用中,有一個方法叫做setXfermode,這個方法需要傳遞一個Xfermode的實例,為了實現這個效果,我們使用PorterDuffXfermode中的SRC_OUT模式,先上代碼再講原理.
首先,準備好兩張圖片,一張是底圖,這個是不變的 也就是最下面那張圖.一張是源圖,也就是最上層那張圖.
還是老套路,自定義控件繼承自View,在構造方法中先初始化畫筆Paint,準備好底圖以及源圖,還有一張跟源圖相同大小的透明圖片,初始化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繪制到畫布上.創建一個新圖層,然后根據將手指的移動軌跡繪制到BmpDST上,將BmpDST繪制到畫布上,最后將BmpSRC以PorterDuff.Mode.SRC_OUT的模式繪制到canvas上.這樣底層圖片BmpText永遠都在最下面的圖層,然后BmpDST與BmpSRC的混合結果將鋪在上面.這樣就可以達到我們想要的結果.
上代碼:
@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);
????//然后把目標圖像畫到畫布上
????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);
}
這里面有一個特別重要的方法就是mBitPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT))
根據PorterDuff的模式不同,展現的效果也不同.SRC_OUT的效果就是按照源圖片BmpSRC以及目標圖片BmpDST的進行組合,最終來繪制源圖片.那這個組合的方式我們來看一下源碼:
/** [Sa * (1 - Da), Sc * (1 - Da)] */
也就是根據上面的規則對源圖片以及目標圖片的顏色ARGB通道來進行組合,當我手勢滑動的時候目標圖片的對應區域的alpha值就變成1了,所以對應的區域就透明了,其他區域時透明的所以對應區域就按源圖展示,這樣就實現了刮刮卡效果了,是不是很神奇!