您当前的位置: 首页 >  ui

命运之手

暂无认证

  • 5浏览

    0关注

    747博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【高级UI】【016】Canvas特效之XferMode

命运之手 发布时间:2021-11-05 11:31:48 ,浏览量:5

什么是XferMode

XferMode全称TransferMode,可翻译为像素转换模式,或色彩混合模式

它指定了,在一个已存在的目标图形上(DST),再绘制一个新图形(SRC),两个图形的像素如何进行混合,形成新的像素

XferMode目前只有一个实现类PorterDuffXfermode,它通过PorterDuff.Mode算法来决定像素如何进行混合

关于这个模式,我们前面在讲Shader时,有详细说明,各种Mode的效果如下

在这里插入图片描述

PorterDuff.Mode算法原理

XferMode的使用方法非常简单,一行代码即可

为Paint设置一个PorterDuffXfermode,之后用它绘制的图形,都会应用该效果


	paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

但是在实际应用中,PorterDuffXfermode的效果往往和我们预期的不一样

这是因为,很多人没有真正理由PorterDuff.Mode算法的工作原理

上面的示意图,只是一种最简单的情景,画SRC的时候,Canvas是全透明的,上面只有DST一个图形元素

实际上,SRC并不是和DST做像素运算,而是和Canvas上已经存在的所有像素做运算

当Canvas上除了SRC还有其它图形,或者Canvas不是全透明,SRC本身有透明度时,光靠上面的示意图就不够了

我们只有通过PorterDuff.Mode的具体算法公式,才能想象出最终的混合图形是什么样的

其实PorterDuff.Mode的算法公式非常简单,去源码里面看一下对应Mode的注释就知道了

以PorterDuff.Mode.SRC_IN为例,它的公式如下


	float alpha_out = alpha_src * alpha_dst;
	float color_out = color_src * alpha_dst;

第一行公式决定了最终像素的透明度,第二行公式决定了最终像素的色彩值

注意,这里的color公式,适用于RGB每个色彩分量,alpha和color的范围均为0-255

这里的乘法是一种简写,实际是要拿乘积再除以255,否则255*255,乘积就超过了255的范围了

PorterDuffXfermode与Layer的组合使用

很多时候,我们只希望SRC与DST进行运算,保持Canvas上其它的图形不变

这时我们就需要使用到Canvas的图层功能了

我们只需要新建一个Layer,在此Layer上面绘制DST和SRC,之前已存在的图形,就不会参与像素运算了

PorterDuffXfermode实现圆角图片


	package com.android.architecture;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.View;

    public class RoundImageView_SrcIn extends View {

        //圆角矩形
        Bitmap dst;
        //真实图像
        Bitmap src;

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

        public RoundImageView_SrcIn(Context context, AttributeSet attrs) {
            super(context, attrs);
            src = BitmapFactory.decodeResource(getResources(), R.drawable.de_ma, null);
            dst = BitmapFactory.decodeResource(getResources(), R.drawable.round_rect, null);
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.argb(255, 150, 150, 150));
            canvas.saveLayer(0, 0, 9999, 9999, null);
            Paint paint = new Paint();
            canvas.drawBitmap(dst, new Rect(0, 0, dst.getWidth(), dst.getHeight()), new Rect(100, 100, 600, 500), paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(src, new Rect(0, 0, src.getWidth(), src.getHeight()), new Rect(100, 100, 600, 500), paint);
        }
    }


Canvas背景 在这里插入图片描述 DST图形 在这里插入图片描述 SRC图形 在这里插入图片描述 最终结果 在这里插入图片描述

PorterDuffXfermode的其它应用

PorterDuffXfermode的模式非常多,用法也非常多,同一种特效可能多种方式都可以实现

由于博客篇幅有限,就不再逐一列举了,想深入了解的,可以看Demo自己学习下

XferMode实现常见特效.zip

大家如果想要在UI方面深入发展的话,其实光看博客是不够的

一定要把常见的特效实现多抄抄,亲手写一遍,基础知识只有掌握透彻了,才能在实践中灵活运用

Demo里包含了圆角效果,倒影效果,心电图效果,波浪效果,裁边效果,橡皮擦效果,刮刮卡效果等

把这些效果都看懂了,对XferMode的理解基本也就透彻了

关注
打赏
1654938663
查看更多评论
立即登录/注册

微信扫码登录

0.0403s