Android Xfermode 学习笔记
2016-03-27 18:54
603 查看
一、概述
Xfermode全名transfer-mode,其作用是实现两张图叠加时的混合效果。
网上流传的关于Xfermode最出名的图来源于AndroidSDK的samples中,名叫Xfermodes.java,效果如下:
二、体验
提炼出Xfermodes.java中的核心代码,自己写了个简单粗暴的demo试试水:
效果如下:
介绍一下几个关键点:
1、关于src和dest
先绘制到canvas上的是dest,后绘制的是src
2、关于硬件加速
在sdkversion>=11时,需要关闭硬件加速(第19行),否则 Mode.CLEAR 、 Mode.DARKEN 、 Mode.LIGHTEN 三种模式下绘制效果不正常
3、saveLayer的作用
Canvas.saveLayer在Canvas.save的基础上,额外自动分配了一个bitmap,使得saveLayer之后的所有绘制都在这个新分配的bitmap上完成。
如果把saveLayer去掉呢?效果就是蓝色矩形跟黄色圆形和灰色背景都进行了 Mode.LIGHTEN 操作:
4、如果不saveLayer
有一种变通的方法,在dest对应bitmap的canvas上绘制src对应的bitmap,这样的目的与saveLayer是一致的,不在当前canvas上直接绘图:
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5326438.html]
三、更多玩法——圆形ImageView
利用Xfermode的特性也可以做出圆形的ImageView来。先画原图,再画圆形,采用 Mode.DST_IN 即可:
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5326438.html]
Xfermode全名transfer-mode,其作用是实现两张图叠加时的混合效果。
网上流传的关于Xfermode最出名的图来源于AndroidSDK的samples中,名叫Xfermodes.java,效果如下:
二、体验
提炼出Xfermodes.java中的核心代码,自己写了个简单粗暴的demo试试水:
public class ImageViewXfermode extends ImageView { public ImageViewXfermode(Context context) { super(context); init(); } public ImageViewXfermode(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ImageViewXfermode(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); } } @Override protected void onDraw(Canvas canvas) { int defaultWidth = dip2px(85); //xml里view的宽度是85dp int defaultdHeight = dip2px(85); //xml里view的高度是85dp if (canvas.getHeight() == defaultWidth && canvas.getHeight() == defaultdHeight) { //拿到黄色圆形的bitmap Bitmap bitcircle = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvascicle = new Canvas(bitcircle); Paint paintcicle = new Paint(Paint.ANTI_ALIAS_FLAG); paintcicle.setColor(0xFFFFCC44); canvascicle.drawCircle(dip2px(30), dip2px(30), dip2px(25), paintcicle); //拿到蓝色矩形的bitmap Bitmap bitrect = Bitmap.createBitmap(defaultWidth, defaultdHeight, Config.ARGB_8888); Canvas canvasrect = new Canvas(bitrect); Paint paintrect = new Paint(Paint.ANTI_ALIAS_FLAG); paintrect.setColor(0xFF66AAFF); canvasrect.drawRect(dip2px(30), dip2px(30), dip2px(80), dip2px(80), paintrect); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Xfermode xfermode = new PorterDuffXfermode(Mode.LIGHTEN); //采用saveLayer,让后续canvas的绘制在自动创建的bitmap上 int cnt = canvas.saveLayer(0, 0, defaultWidth, defaultdHeight, null, Canvas.ALL_SAVE_FLAG); //先画圆形,圆形是dest canvas.drawBitmap(bitcircle, 0, 0, paint); paint.setXfermode(xfermode); //后画矩形,矩形是src canvas.drawBitmap(bitrect, 0, 0, paint); paint.setXfermode(null); canvas.restoreToCount(cnt); } else { super.onDraw(canvas); } } private int dip2px(float dip) { float scale = getResources().getDisplayMetrics().density; return (int)(dip * scale + 0.5f); } }
效果如下:
介绍一下几个关键点:
1、关于src和dest
先绘制到canvas上的是dest,后绘制的是src
2、关于硬件加速
在sdkversion>=11时,需要关闭硬件加速(第19行),否则 Mode.CLEAR 、 Mode.DARKEN 、 Mode.LIGHTEN 三种模式下绘制效果不正常
3、saveLayer的作用
Canvas.saveLayer在Canvas.save的基础上,额外自动分配了一个bitmap,使得saveLayer之后的所有绘制都在这个新分配的bitmap上完成。
如果把saveLayer去掉呢?效果就是蓝色矩形跟黄色圆形和灰色背景都进行了 Mode.LIGHTEN 操作:
4、如果不saveLayer
有一种变通的方法,在dest对应bitmap的canvas上绘制src对应的bitmap,这样的目的与saveLayer是一致的,不在当前canvas上直接绘图:
@Override protected void onDraw(Canvas canvas) { int defaultWidth = dip2px(85); //xml里view的宽度是85dp int defaultdHeight = dip2px(85); //xml里view的高度是85dp if (canvas.getHeight() == defaultWidth && canvas.getHeight() == defaultdHeight) { //拿到黄色圆形的bitmap Bitmap bitcircle = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvascicle = new Canvas(bitcircle); Paint paintcicle = new Paint(Paint.ANTI_ALIAS_FLAG); paintcicle.setColor(0xFFFFCC44); canvascicle.drawCircle(dip2px(30), dip2px(30), dip2px(25), paintcicle); //拿到蓝色矩形的bitmap Bitmap bitrect = Bitmap.createBitmap(defaultWidth, defaultdHeight, Config.ARGB_8888); Canvas canvasrect = new Canvas(bitrect); Paint paintrect = new Paint(Paint.ANTI_ALIAS_FLAG); paintrect.setColor(0xFF66AAFF); canvasrect.drawRect(dip2px(30), dip2px(30), dip2px(80), dip2px(80), paintrect); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Xfermode xfermode = new PorterDuffXfermode(Mode.LIGHTEN); //设置setXfermode paint.setXfermode(xfermode); //在圆形的canvas上画矩形,先画圆形,圆形是dest,后画矩形,矩形是src canvascicle.drawBitmap(bitrect, 0, 0, paint); paint.setXfermode(null); //将圆形canvas上画出来的结果绘制到canvas上 canvas.drawBitmap(bitcircle, 0.0f, 0.0f, paint); } else { super.onDraw(canvas); } }
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5326438.html]
三、更多玩法——圆形ImageView
利用Xfermode的特性也可以做出圆形的ImageView来。先画原图,再画圆形,采用 Mode.DST_IN 即可:
@Override protected void onDraw(Canvas canvas) { int defaultWidth = dip2px(85); //xml里view的宽度是85dp int defaultdHeight = dip2px(85); //xml里view的高度是85dp Drawable drawable = getDrawable(); if (canvas.getHeight() == defaultWidth && canvas.getHeight() == defaultdHeight && drawable instanceof BitmapDrawable) { //setBackgroundColor(Color.TRANSPARENT); //拿到原图的bitmap Bitmap bitimg = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvasimg = new Canvas(bitimg); Matrix matrix = new Matrix(); matrix.setScale(defaultWidth * 1.0f / drawable.getIntrinsicWidth(), defaultdHeight * 1.0f / drawable.getIntrinsicHeight()); Paint paintimg = new Paint(Paint.ANTI_ALIAS_FLAG); canvasimg.drawBitmap(((BitmapDrawable)drawable).getBitmap(), matrix, paintimg); //拿到圆形的bitmap Bitmap bitcircle = Bitmap.createBitmap(defaultWidth, defaultdHeight, Config.ARGB_8888); Canvas canvascircle = new Canvas(bitcircle); Paint paintcircle = new Paint(Paint.ANTI_ALIAS_FLAG); paintcircle.setColor(0xFF66AAFF); canvascircle.drawCircle(dip2px(85 / 2.0f), dip2px(85 / 2.0f), dip2px(85 / 2.0f), paintcircle); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Xfermode xfermode = new PorterDuffXfermode(Mode.DST_IN); //采用saveLayer,让后续canvas的绘制在自动创建的bitmap上 int cnt = canvas.saveLayer(0, 0, defaultWidth, defaultdHeight, null, Canvas.ALL_SAVE_FLAG); //先画原图,原图是dest canvas.drawBitmap(bitimg, 0, 0, paint); paint.setXfermode(xfermode); //后画圆形,圆形是src canvas.drawBitmap(bitcircle, 0, 0, paint); paint.setXfermode(null); canvas.restoreToCount(cnt); } else { super.onDraw(canvas); } }
[转载请保留本文地址:http://www.cnblogs.com/goagent/p/5326438.html]
相关文章推荐
- 一个三年Android开发的总结-常用的git技巧与误区
- android 从手机相册中选择一张照片
- Android Studio不能获取远程依赖包的解决方法
- Android Scroll详解(一):基础知识
- GCM(谷歌云推送)客户端服务器端开发全指南(客户端)
- com/android/dx/command/dexer/Main : Unsupported major.minor version 52.0
- Android5.0 之 SnackBar
- Android真机调试时,Device的连接容易断开
- #Android学习#Animation之布局动画
- android自定义View(一):扩展方式(继承)带有预置数据 和 删除键的自定义EditText
- android动画详解五 layout,插值与评估器
- Android ProgressBar 样式大全
- android studio 2.1 preview4 之 gradle插件问题
- 内部Handler类引起内存泄露
- AndroidStudio中代码混淆以及打包操作
- Android ORM应用开发框架KJFrameForAndroid使用详解
- Android初试--Android中的ContentProvider(3)
- 给TextView加背景
- Android M上VideoCall中Audio的管理(2016.05.27 新增CallsManager部分)
- android 获得当前进程的名字