Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android基礎入門教程——8.3.7 Paint API之—— Xfermode與PorterDuff詳解(四)

Android基礎入門教程——8.3.7 Paint API之—— Xfermode與PorterDuff詳解(四)

編輯:關於Android編程

 

 

本節引言:

上節我們寫了關於Xfermode與PorterDuff使用的第一個例子:圓角&圓形圖片ImageView的實現,
我們體會到了PorterDuff.Mode.DST_IN給我們帶來的好處,本節我們繼續來寫例子練練手,
還記得Android基礎入門教程——8.3.2 繪圖類實戰示例給大家帶來的拔掉美女衣服的實現嗎?

title=

當時我們的實現方案是,將手指觸碰區域附近的20*20個像素點設置為透明,效果圖是這樣的:

title=

不知道你有沒有發現一個問題,我們擦美女衣服的時候,擦拭的時候都是方塊的,但是我們畫圖板
畫圖的時候,劃線都是很平滑的,有沒有辦法將兩者結合起來,我們擦衣服時也是圓滑的呢?
答案肯定是有的,就是使用Xfermode咯!本節我們使用另一個模式,DST_OUT模式!
在不相交的地方繪制目標圖

title=

如果你忘記了某個模式或者連18種模式都沒見過的話,那麼請移步:
Android基礎入門教程——8.3.5 Paint API之—— Xfermode與PorterDuff詳解(二)
另外,還是要貼下PorterDuff.Mode的效果圖:

title=

嗯,話不多說,開始本節內容~


1.要實現的效果圖以及實現流程分析:

要實現的效果圖

title=

title=嗯,不知道你看了那個Gif圖多少次了呢?不知道圖中是否適合大家的口味,小豬
是從別人的APP上扒下來的,別問我番號或者留郵箱什麼的,我什麼都不知道~找番什麼的,
問群裡的老司機——基神吧,好的,我們來分析下實現流程吧~

我們來說說原理,其實就是兩個Bitmap,一前一後,前面的是穿著衣服的,後面的是沒穿衣服的,
然後通過一個Path來記錄用戶繪制出來的圖形,然後為我們的畫筆設置DST_OUT的模式,那麼
與Path重疊部分的DST(目標圖),就是穿著衣服的圖,會變成透明!好哒,很簡單!
我們再慢慢細化! 首先我們需要兩個Bitmap,用來存儲前後兩張圖片,這裡我們讓兩個Bitmap都全屏! 接著設置下畫筆,圓角,筆寬,抗鋸齒等! 再接著定義一個畫Path,即用戶繪制區域的方法,設置Xfermode後畫區域而已! 然後重寫onTouchEvent方法,這部分和之前的自定義畫圖板是一樣的! 最後重寫onDraw()方法,先繪制背景圖片,調用用戶繪制區域的方法,再繪制前景圖片!

可能看上去有點復雜,其實不然,代碼超簡單的說~


2.代碼實現:

直接就一個自定義View——StripMeiZi.java

/**
 * Created by Jay on 2015/10/25 0025.
 */
public class StripMeiZi extends View{

    private Paint mPaint = new Paint();
    private Path mPath = new Path();
    private Canvas mCanvas;
    private Bitmap mBeforeBitmap;
    private Bitmap mBackBitmap;
    private int mLastX,mLastY;
    private int screenW, screenH; //屏幕寬高
    private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);


    public StripMeiZi(Context context) {
        this(context, null);
    }

    public StripMeiZi(Context context, AttributeSet attrs) {
        super(context, attrs);
        screenW = ScreenUtil.getScreenW(context);
        screenH = ScreenUtil.getScreenH(context);
        init();
    }


    public StripMeiZi(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        //背後圖片,這裡讓它全屏
        mBackBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi_back);
        mBackBitmap = Bitmap.createScaledBitmap(mBackBitmap, screenW, screenH, false);
        //前面的圖片,並繪制到Canvas上
        mBeforeBitmap = Bitmap.createBitmap(screenW, screenH, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBeforeBitmap);
        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(),
                R.mipmap.meizi_before), null, new RectF(0, 0, screenW, screenH), null);
        //畫筆相關的設置
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND); // 圓角
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 圓角
        mPaint.setStrokeWidth(80);    // 設置畫筆寬
    }

    private void drawPath() {
        mPaint.setXfermode(mXfermode);
        mCanvas.drawPath(mPath, mPaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBackBitmap, 0, 0, null);
        drawPath();
        canvas.drawBitmap(mBeforeBitmap, 0, 0, null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:

                int dx = Math.abs(x - mLastX);
                int dy = Math.abs(y - mLastY);

                if (dx > 3 || dy > 3)
                    mPath.lineTo(x, y);

                mLastX = x;
                mLastY = y;
                break;
        }
        invalidate();
        return true;
    }
}

 

  1. 上一頁:
  2. 下一頁: