關於 Xfermode 正確理解姿勢

作者: 夏至 歡迎轉載,但保留這段申明
http://blog.csdn.net/u011418943/article/details/79310254

首先,先拋出一張 Google 的示例圖,這是一張讓人尷尬的效果圖:
這裏寫圖片描述

爲啥這麼說?

因爲這張圖爲了能夠顯示 PorterDuff 的效果,代碼是做了一些效果的,這就導致了一些小夥伴在寫 demo 理解的時候,發現跟 Google 的效果不一致,從而產生疑問,是不是我寫錯了?哪裏不一致呢?比如我寫了 SRC_IN 這個模式,按照上面的效果,應該是這樣的:
這裏寫圖片描述

而實際上,卻是這樣的:
這裏寫圖片描述

咦,爲啥是這樣的,我進入的姿勢不對? 這裏寫圖片描述

不要急,這裏我想說的是,你沒有理解錯,只是源碼做了處理而已。

1、ApiDemo 的代碼

先看一下 ApiDemo 的代碼, src 和 dst 是一張圖片,而玄機就在這裏,首先先看 src(即藍色的圖片)的代碼:

  // create a bitmap with a rect, used for the "src" image
    static Bitmap makeSrc(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFF66AAFF);
        c.drawRect(w/3, h/3, w*19/20, h*19/20, p);
        return bm;
    }

可以看到,雖然設置了 寬 和 高,但是實際canvas在畫的時候,卻沒有填滿,而留一段空白區域出來。我們在四周加一個邊框,看一下效果:
這裏寫圖片描述

可以看到,這裏留了一大段的空白區域,同理,dst 的圖片也是如此:
這裏寫圖片描述
而 SRC_IN 是兩者相較的地方繪製,那麼上面這兩張圖繪製的結果,就只能是這樣:
這裏寫圖片描述

真相終於大白了,原來是這廝
這裏寫圖片描述

嗯,那麼,來一段幫助你理解這些模式的代碼,去折騰吧:

public class XfermodeView extends View {
    private static final String TAG = "XfermodeView";

    private PorterDuffXfermode mPdXfermode;   //定義PorterDuffXfermode變量
    //定義MODE常量,等下直接改這裏即可進行測試
    private static PorterDuff.Mode PD_MODE = PorterDuff.Mode.SRC_IN         ;
    private int mScreenW, mScreenH; //屏幕寬高
    private int mWidth = 200;      //繪製的圖片寬高
    private int nHeight = 200;
    private Bitmap mSrcBitmap, mDstBitmap;     //上層SRC的Bitmap和下層Dst的Bitmap
    private Paint mShowpaint;

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

    public XfermodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mShowpaint = new Paint();
        mShowpaint.setStyle(Paint.Style.STROKE);
        mShowpaint.setStrokeWidth(2);
        mScreenW = ScreenUtil.getScreenW(context);
        mScreenH = ScreenUtil.getScreenH(context);
        //創建一個PorterDuffXfermode對象
        mPdXfermode = new PorterDuffXfermode(PD_MODE);
        //實例化兩個Bitmap
        mSrcBitmap = makeSrc(mWidth, nHeight);
        mDstBitmap = makeDst(mWidth, nHeight);
    }

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


    //定義一個繪製圓形Bitmap的方法,作爲dst圖
    private Bitmap makeDst(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFF26AAD1);
        c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);
        //畫四周的邊框線
        mShowpaint.setColor(0xFF26AAD1);
        c.drawRect(0,0,w,h, mShowpaint);
        return bm;
    }

    //定義一個繪製矩形的Bitmap的方法,作爲src圖
    private Bitmap makeSrc(int w, int h) {
        Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(0xFFFFCE43);
        Log.d(TAG, "zsr --> makeSrc: "+w/3+"  "+w*19/20);
        c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p);

        //畫四周的邊框線

        mShowpaint.setColor(0xFFFFCE43);
        mShowpaint.setStyle(Paint.Style.STROKE);

        c.drawRect(0,0,w,h,mShowpaint);
        return bm;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setFilterBitmap(false);
        paint.setStyle(Paint.Style.FILL);
        //繪製SRC上層的矩形Bitmap
        canvas.drawBitmap(mSrcBitmap, (mScreenW / 3 - mWidth) / 2, (mScreenH / 2 - nHeight) / 2, paint);
        //繪製DST下層的原型Bitmap
        canvas.drawBitmap(mDstBitmap, (mScreenW / 3 - mWidth) / 2 + mScreenW / 3, (mScreenH / 2 - nHeight) / 2, paint);



        //創建一個圖層,在圖層上演示圖形混合後的效果
        int sc = canvas.saveLayer(0, 0, mScreenW, mScreenH, null, Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(mDstBitmap, (mScreenW / 3 - mWidth) / 2 + mScreenW / 3 * 2,
                (mScreenH / 2 - nHeight) / 2, paint);     //繪製i
        //設置Paint的Xfermode
        paint.setXfermode(mPdXfermode);
        canvas.drawBitmap(mSrcBitmap, (mScreenW / 3 - mWidth) / 2 + mScreenW / 3 * 2,
                (mScreenH / 2 - nHeight) / 2, paint);
        paint.setXfermode(null);
        // 還原畫布
        canvas.restoreToCount(sc);

        /**
         * 畫圖片的邊框,便於理解
         */
        // src line
        int srcleft = (mScreenW / 3 - mWidth) / 2 + mScreenW / 3 * 2;
        int srctop = (mScreenH / 2 - nHeight) / 2;
        mShowpaint.setColor(0xFFFFCE43);
        canvas.drawRect(srcleft,srctop,srcleft + mWidth,srctop+ nHeight,mShowpaint);

        // des line,因爲位置一樣,加4減4,能看出效果
        mShowpaint.setColor(0xFF26AAD1);
        canvas.drawRect(srcleft + 4,srctop + 4,
                srcleft + mWidth - 4,srctop+ nHeight -4 ,mShowpaint);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章