上一节概述了Paint进阶需要掌握的API,这一节针对图层混合模式进行讲解,主要是Xfermode的使用。

1.概念

图层混合模式是将所绘制的像素与canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,最终更新canvas中最终显示的像素值。

2.使用场景

图层混合模式使用的三种场景:1.ComposeShader(混合渲染);2.画笔的Paint.setXfermode();3.PorterDuffColorFilter(颜色过滤器)。

3.setXfermode使用

1.图层混合模式使用时必须禁止硬件加速

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

2.离屏绘制

//        //离屏绘制int layerId = canvas.saveLayer(0,0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);//......中间进行绘制//canvas.restoreToCount(layerId);

3.绘制


//        //目标图canvas.drawBitmap(createRectBitmap(mWidth, mHeight), 0, 0, mPaint);
//        //设置混合模式mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
//        //源图,重叠区域右下角部分canvas.drawBitmap(createCircleBitmap(mWidth, mHeight), 0, 0, mPaint);
//        //清除混合模式mPaint.setXfermode(null);

完整的XferMode代码:

public class XfermodeView extends View {private Paint mPaint;private int mWidth, mHeight;public XfermodeView(Context context) {this(context, null);}public XfermodeView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {//初始化画笔mPaint = new Paint();mPaint.setColor(Color.RED);mPaint.setStyle(Paint.Style.FILL_AND_STROKE);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight = MeasureSpec.getSize(heightMeasureSpec);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//1.ComposeShader//2.画笔Paint.setXfermode()//3.PorterDuffColorFilter//禁止硬件加速setLayerType(View.LAYER_TYPE_SOFTWARE, null);setBackgroundColor(Color.GRAY);//        //离屏绘制int layerId = canvas.saveLayer(0,0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);//        //目标图Dstcanvas.drawBitmap(createRectBitmap(mWidth, mHeight), 0, 0, mPaint);
//        //设置混合模式mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
//        //源图Src,重叠区域右下角部分canvas.drawBitmap(createCircleBitmap(mWidth, mHeight), 0, 0, mPaint);
//        //清除混合模式mPaint.setXfermode(null);
//canvas.restoreToCount(layerId);}//画矩形Dstpublic Bitmap createRectBitmap(int width, int height) {Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG);dstPaint.setColor(0xFF66AAFF);//蓝色canvas.drawRect(new Rect(width / 20, height / 3, 2 * width / 3, 19 * height / 20), dstPaint);return bitmap;}//画圆srcpublic Bitmap createCircleBitmap(int width, int height) {Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);Paint scrPaint = new Paint(Paint.ANTI_ALIAS_FLAG);scrPaint.setColor(0xFFFFCC44);//黄色canvas.drawCircle(width * 2 / 3, height / 3, height / 4, scrPaint);return bitmap;}}

运行后的效果图:

Xfermode模式

从代码中可以看待现在设置的混合模式为ADD,Xfermode有18种类型,详细的解释见下图

                //所绘制不会提交到画布上new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//显示上层绘制的图像new PorterDuffXfermode(PorterDuff.Mode.SRC),//显示下层绘制图像new PorterDuffXfermode(PorterDuff.Mode.DST),//正常绘制显示,上下层绘制叠盖new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//上下层都显示,下层居上显示new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//取两层绘制交集,显示上层new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//取两层绘制交集,显示下层new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//取上层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//取下层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//取上层交集部分与下层非交集部分new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//取下层交集部分与上层非交集部分new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//去除两图层交集部分new PorterDuffXfermode(PorterDuff.Mode.XOR),//取两图层全部区域,交集部分颜色加深new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//取两图层全部区域,交集部分颜色点亮new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//取两图层交集部分,颜色叠加new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//取两图层全部区域,交集部分滤色new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//取两图层全部区域,交集部分饱和度相加new PorterDuffXfermode(PorterDuff.Mode.ADD),//取两图层全部区域,交集部分叠加new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)

18种模式对应的效果图如下所示

上图的实现代码的效果图完整代码如下:

public class XfermodesView extends View {private static int W = 250;private static int H = 250;private static final int ROW_MAX = 4;   // number of samples per rowprivate Bitmap mSrcB;private Bitmap mDstB;private Shader mBG;     // background checker-board pattern//其中Sa全称为Source alpha表示源图的Alpha通道;Sc全称为Source color表示源图的颜色;Da全称为Destination alpha表示目标图的Alpha通道;Dc全称为Destination color表示目标图的颜色,[...,..]前半部分计算的是结果图像的Alpha通道值,“,”后半部分计算的是结果图像的颜色值。//效果作用于src源图像区域private static final Xfermode[] sModes = {//所绘制不会提交到画布上new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//显示上层绘制的图像new PorterDuffXfermode(PorterDuff.Mode.SRC),//显示下层绘制图像new PorterDuffXfermode(PorterDuff.Mode.DST),//正常绘制显示,上下层绘制叠盖new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//上下层都显示,下层居上显示new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//取两层绘制交集,显示上层new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//取两层绘制交集,显示下层new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//取上层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//取下层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//取上层交集部分与下层非交集部分new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//取下层交集部分与上层非交集部分new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//去除两图层交集部分new PorterDuffXfermode(PorterDuff.Mode.XOR),//取两图层全部区域,交集部分颜色加深new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//取两图层全部区域,交集部分颜色点亮new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//取两图层交集部分,颜色叠加new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//取两图层全部区域,交集部分滤色new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//取两图层全部区域,交集部分饱和度相加new PorterDuffXfermode(PorterDuff.Mode.ADD),//取两图层全部区域,交集部分叠加new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)};private static final String[] sLabels = {"Clear", "Src", "Dst", "SrcOver","DstOver", "SrcIn", "DstIn", "SrcOut","DstOut", "SrcATop", "DstATop", "Xor","Darken", "Lighten", "Multiply", "Screen", "Add","Overlay"};public XfermodesView(Context context) {this(context, null);}public XfermodesView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodesView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);if (windowManager != null) {DisplayMetrics display = new DisplayMetrics();windowManager.getDefaultDisplay().getMetrics(display);W = H = (display.widthPixels - 64) / ROW_MAX; //得到矩形}//1,API 14之后,有些函数不支持硬件加速,需要禁用setLayerType(View.LAYER_TYPE_SOFTWARE, null);mSrcB = makeSrc(W, H);mDstB = makeDst(W, H);//根据width和height创建空位图,然后用指定的颜色数组colors来从左到右从上至下一次填充颜色//make a ckeckerboard patternBitmap bm = Bitmap.createBitmap(new int[]{0xFFFFFFFF, 0xFFCCCCCC, 0xFFCCCCCC, 0xFFFFFFFF}, 2, 2, Bitmap.Config.RGB_565);mBG = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);Matrix m = new Matrix();m.setScale(6, 6);mBG.setLocalMatrix(m);}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawColor(Color.WHITE);Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);labelP.setTextAlign(Paint.Align.CENTER);Paint paint = new Paint();paint.setFilterBitmap(false);canvas.translate(15, 35);int x = 0;int y = 0;for (int i = 0; i < sModes.length; i++) {// draw the borderpaint.setStyle(Paint.Style.STROKE);paint.setShader(null);canvas.drawRect(x - 0.5f, y - 0.5f, x + W + 0.5f, y + H + 0.5f, paint);// draw the checker-board patternpaint.setStyle(Paint.Style.FILL);paint.setShader(mBG);canvas.drawRect(x, y, x + W, y + H, paint);// 使用离屏绘制int sc = canvas.saveLayer(x, y, x + W, y + H, null);canvas.translate(x, y);canvas.drawBitmap(makeDst(2 * W / 3, 2 * H / 3), 0, 0, paint);paint.setXfermode(sModes[i]);canvas.drawBitmap(makeSrc(2 * W / 3, 2 * H / 3), W / 3, H / 3, paint);paint.setXfermode(null);canvas.restoreToCount(sc);// draw the labellabelP.setTextSize(20);canvas.drawText(sLabels[i], x + W / 2, y - labelP.getTextSize() / 2, labelP);x += W + 10;// wrap around when we've drawn enough for one rowif ((i % ROW_MAX) == ROW_MAX - 1) {x = 0;y += H + 30;}}}// create a bitmap with a circle, used for the "dst" image// 画圆一个完成的圆static 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(0xFFFFCC44);//黄色c.drawOval(new RectF(0, 0, w, h), p);return bm;}// 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(0, 0, w * 19 / 20, h * 19 / 20, p);return bm;}}

刮刮卡效果

最后附上一个应用实例,效果图如下

完整代码

public class XfermodeEraserView extends View {private Paint  mPaint;private Bitmap mDstBmp, mSrcBmp, mTxtBmp;private Path mPath;public XfermodeEraserView(Context context) {this(context, null);}public XfermodeEraserView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodeEraserView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {//初始化画笔mPaint = new Paint();mPaint.setColor(Color.RED);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(80);//禁用硬件加速setLayerType(View.LAYER_TYPE_SOFTWARE, null);//初始化图片对象mTxtBmp = BitmapFactory.decodeResource(getResources(), R.drawable.result);mSrcBmp = BitmapFactory.decodeResource(getResources(), R.drawable.eraser);mDstBmp = Bitmap.createBitmap(mSrcBmp.getWidth(), mSrcBmp.getHeight(), Bitmap.Config.ARGB_8888);//路径(贝塞尔曲线)mPath = new Path();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制刮奖结果canvas.drawBitmap(mTxtBmp, 0, 0, mPaint);//使用离屏绘制int layerID = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);//先将路径绘制到 bitmap上Canvas dstCanvas = new Canvas(mDstBmp);dstCanvas.drawPath(mPath, mPaint);//绘制 目标图像canvas.drawBitmap(mDstBmp, 0, 0, mPaint);//设置 模式 为 SRC_OUT, 擦橡皮区域为交集区域需要清掉像素mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));//绘制源图像canvas.drawBitmap(mSrcBmp, 0, 0, mPaint);mPaint.setXfermode(null);canvas.restoreToCount(layerID);}private float mEventX, mEventY;@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mEventX = event.getX();mEventY = event.getY();mPath.moveTo(mEventX, mEventY);break;case MotionEvent.ACTION_MOVE:float endX = (event.getX() - mEventX) / 2 + mEventX;float endY = (event.getY() - mEventY) / 2 + mEventY;//画二阶贝塞尔曲线mPath.quadTo(mEventX, mEventY, endX, endY);mEventX = event.getX();mEventY = event.getY();break;}invalidate();return true; //消费事件}}

Xfermode的使用其实不难,主要是学会灵活使用,最后附上demo:https://github.com/987570437/PaintDemo

Android Paint 进阶之 图层混合模式(Xfermode)相关推荐

  1. Android Paint 进阶之滤镜效果(ColorFilter)

    上一节整理了图层混合模式(Xfermode),这一节主要整理滤镜(ColorFilter)的使用. 分类 滤镜ColorFilter有三个子类,分别是LightingColorFilter.Porte ...

  2. Android 橡皮擦功能,图层混合模式PorterDuff.Mode实践

    先上效果图: 使用图层混合模式注意点: 1.图层类型设置为软件类型,有些api不支持硬件类型,默认视图是没有开启图层的 setLayerType(LAYER_TYPE_SOFTWARE, null); ...

  3. Android高级进阶——绘图篇(五)setXfermode 设置混合模式

    一.GPU硬件加速 1.概述 GPU英文全称Graphic Processing Unit,中文翻译为"图形处理器".与CPU不同,GPU是专门为处理图形任务而产生的芯片. 在GP ...

  4. 柔光混合模式android,滤色与柔光两种图层混合模式的理解和应用实例

    上午逛了下许久没有来的网站,很有一种久违的感觉,随即浏览了下,发现里面有个帖子叫做"唯美效果轻松做",仔细阅读了一遍,体会较深.首先的感觉是整个图片处理过程简单明了,短短几步就达到 ...

  5. Android Paint、Canvas、Matrix使用讲解(一、Paint)

    http://blog.csdn.net/tianjian4592/article/details/44336949 好了,前面主要讲了Animation,Animator 的使用,以及桌面火箭效果和 ...

  6. Android Paint以及ColorFilter等

    我们可以通过Paint中大量的setter方法来为画笔设置属性: 这些属性大多我们都可以见名知意,很好理解,即便如此,哥还是带大家过一遍逐个剖析其用法,其中会不定穿插各种绘图类比如Canvas.Xfe ...

  7. Android 颜色渲染(九) PorterDuff及Xfermode详解

    Android 颜色渲染(九)  PorterDuff及Xfermode详解 之前已经讲过了除ComposeShader之外Shader的全部子类, 在讲ComposeShader(组合渲染)之前,  ...

  8. Android伸手党系列之六:Android开发进阶

    这是android伸手党知识收集系列的第六篇,来整理android开发进阶相关知识:Window,View,事件分发,NFC,蓝牙等. Android View 简介 View的简介 那些你应该知道却 ...

  9. Android Paint类

    1. Paint常用方法 setColor(int),设置画笔的颜色 setAlpha(int),设置画笔的透明度 setARGB(int a, int r, int g, int b),设置画笔的颜 ...

最新文章

  1. 某些列满足特定条件,然后改变另外的某些列的值(Python)
  2. Kubernetes 新玩法:在 yaml 中编程
  3. 100%测试覆盖率真的有用吗?
  4. javascript高级程序设计-Array迭代及归并
  5. 随机抽样java_实现随机抽样【随机数生成问题】
  6. BZOJ 3295: [Cqoi2011]动态逆序对 cdq分治
  7. Hive insert into小文件问题优化解决
  8. 高性能服务框架-Dubbo实战教程,看这一篇就够了
  9. 2020年中华人民共和国行政区划代码
  10. 中小型局域网上网管理组网方案
  11. 如何设置 RecyclerView Item内子控件点击事件
  12. 【MySQL】深入分析MySQL索引机制的实现
  13. python网络爬虫网易云音乐_一篇文章带你用Python网络爬虫实现网易云音乐歌词抓取...
  14. 微信文章实现代码高亮
  15. 杨辉三角 (java语言)
  16. 小程序云开发教程七:贴子的详情及评论功能
  17. 计算机桌面屏幕怎么设置全屏,如何让电脑显示器屏幕显示全屏
  18. 网络错误修复工具:Network Fault Repair Tool Build20160414
  19. 如何监控和改进用于深度学习的 GPU 使用率?
  20. 字扩展,位扩展和字位扩展

热门文章

  1. 空间计量溢出效应的动态GIF演示
  2. 51单片机——7段数码管的循环显示
  3. WIFI 断线原因总结
  4. MySQL 性能优化实战
  5. TCP IP网络编程笔记——尹圣雨
  6. web期末网站设计大作业 奶茶店网站美食餐饮网站设计与实现(HTML+CSS+JavaScript)
  7. VC++报错:无法打开源文件“new.h”...
  8. 爬虫日常-12306自动购票程序
  9. 施工图审制度全面取消:图审单位退场,整顿建筑设计行业乱象
  10. 【CAN模块】解决主控内部无终端电阻两路CAN外部回环通信问题