Android Paint之 setXfermode PorterDuffXfermode 讲解

我正在参加 CSDN 2015博客之星评选 感恩分享活动,如果觉得文章还不错,请投个票鼓励下吧:http://vote.blog.csdn.net/blogstar2015/candidate?username=tianjian4592


尊重原创,欢迎转载,转载请注明: FROM  GA_studio   http://blog.csdn.net/tianjian4592


前面关于paint的方法讲解里,讲到 setXfermode 就截止了,原因有两个:

1. 那篇文章已经太长了,我自己都看不下去了;

2. setXfermode 在paint 里占有至关重要的地位;

基于以上两个原因,我们一起来看看这个方法有何妙用。

首先我们还是来看看关于这个方法的说明:

    /**
     * Set or clear the xfermode object. - 设置或清除xfermode对象;
     * Pass null to clear any previous xfermode. - 传递null以清除任何以前的xfermode。
     * As a convenience, the parameter passed is also returned. - 为方便起见,也返回传递的参数。
     *
     * @return         xfermode
     */
    public Xfermode setXfermode(Xfermode xfermode) {
        int xfermodeNative = 0;
        if (xfermode != null)
            xfermodeNative = xfermode.native_instance;
        native_setXfermode(mNativePaint, xfermodeNative);
        mXfermode = xfermode;
        return xfermode;
    }

这个方法传进一个 Xfermode 对象,而打开 Xfermode 发现里面没有提供任何可用的构造函数或方法,ctrl +T 看到它有三个子类:




前两个子类 AvoidXfermode 和 PixelXorXfermode 大家可以看到都已经被划上了斜线,下面就简单提及一下,咱们的重点在 PorterDuffXfermode :

1. AvoidXfermode:

    /** This xfermode draws, or doesn't draw, based on the destination's
     * distance from an op-color.
     *
     * There are two modes, and each mode interprets a tolerance value.
     *
     * Avoid: In this mode, drawing is allowed only on destination pixels that
     * are different from the op-color.
     * Tolerance near 0: avoid any colors even remotely similar to the op-color
     * Tolerance near 255: avoid only colors nearly identical to the op-color
     * Tolerance near 0: draw only on colors that are nearly identical to the op-color
     * Tolerance near 255: draw on any colors even remotely similar to the op-color
     */
    public AvoidXfermode(int opColor, int tolerance, Mode mode) {
        if (tolerance < 0 || tolerance > 255) {
            throw new IllegalArgumentException("tolerance must be 0..255");
        }
        native_instance = nativeCreate(opColor, tolerance, mode.nativeInt);
    }

咱们把它上面的说明看下就很清楚了:

xfermode 是否绘制,基于目标色和参数 op-color 的差距;

其中有两种模式,分别为 Avoid 和 TARGET:

Avoid模式:只会在目标像素值和 op-color "不一样" 的地方进行绘制;

Target模式:只会在目标像素值和 op-color "一样" 的地方进行绘制;

上面的"一样" 和 "不一样" 我都打上了引号,并不是指严格意义上的一样,而是只要在可容忍范围内就代表一样,这个可容忍范围,就是容差值(tolerance),0 代表最小容差,即得和 op-color 真正意义上一样才 ok ,255 则代表最大容差,只要有一点相近,则ok;

咱们一起来看个小例子:

先在网上找个图案,用PS去掉周围部分,主体改为纯色;


                                  


当我们使用PS里的魔棒创立选区的时候,发现一次只选取了其中最相近的一部分,这时候可以看到容差为5,但我们的目的是想把图形周围近似的蓝灰色都选中该怎么办呢?容差这时候就起作用了,改大容差,就相当于调大近似度,这个概念和我们里面的容差值是一样的,希望这样说便于理解,我们看下对比图,调到50 一下就可以选中外层所有蓝灰色:


                                               


好,我们现在有了一个纯色的图标,假定我们现在有一个需求,需要在某种操作下将图标变色,类似微信底部的tab图标,未选中时时白色,选中时是绿色,这个时候我们就可以用

AvoidXfermode 进行实现,我们一起看看要怎么做:

1. 给paint 设置要变换的颜色和图层混合模式为 AvoidXfermode;

2. 绘制图标;

3. 再绘制对应色块;

由于是对对应颜色进行替换,所以也就形成了图标变色的效果,一起来看看代码:

public class AvoidXfermodeView extends View {

    private Paint mBitmapPaint, mAvoidPaint;

    private int mTotalWidth, mTotalHeight;

    private Bitmap mBitmap;
    private int mBitWidth, mBitHeight;
    private Rect mOriginSrcRect, mOriginDestRect;
    private Rect mAvoidSrcRect, mAvoidDestRect;

    private AvoidXfermode mAvoidXfermode;

    public AvoidXfermodeView(Context context) {
        super(context);
        initPaint();
        initBitmap();
        // 对蓝色相近的颜色进行替换
        mAvoidXfermode = new AvoidXfermode(Color.BLUE, 150, Mode.TARGET);
    }

    private void initBitmap() {
        mBitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.bluelogo)).getBitmap();
        mBitWidth = mBitmap.getWidth();
        mBitHeight = mBitmap.getHeight();
    }

    private void initPaint() {
        mBitmapPaint = new Paint();
        // 去锯齿
        mBitmapPaint.setAntiAlias(true);
        // 防抖动
        mBitmapPaint.setDither(true);
        // 图像过滤
        mBitmapPaint.setFilterBitmap(true);

        // 使用上面属性创建一个新paint
        mAvoidPaint = new Paint(mBitmapPaint);
        // 颜色设置为红色
        mAvoidPaint.setColor(Color.RED);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 绘制原图
        canvas.drawBitmap(mBitmap, mOriginSrcRect, mOriginDestRect, mBitmapPaint);

        // 绘制用于变色图
        canvas.drawBitmap(mBitmap, mAvoidSrcRect, mAvoidDestRect, mAvoidPaint);
        // 设置图层混合模式
        mAvoidPaint.setXfermode(mAvoidXfermode);
        // 绘制色块进行混合,得到最终效果
        canvas.drawRect(mAvoidDestRect, mAvoidPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mTotalWidth = w;
        mTotalHeight = h;

        mOriginSrcRect = new Rect(0, 0, mBitWidth, mBitHeight);
        // 为了让图水平居中
        int left = (mTotalWidth - mBitWidth) / 2;
        mOriginDestRect = new Rect(left, 0, left + mBitWidth, mBitHeight);

        mAvoidSrc
  • 24
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值