关于 Xfermode 正确理解姿势

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011418943/article/details/79310254

作者: 夏至 欢迎转载,但保留这段申明
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);
    }
}

猜你喜欢

转载自blog.csdn.net/u011418943/article/details/79310254