您的位置:首页 > 移动开发 > Android开发

Android Xfermode 学习笔记

2016-03-27 18:54 603 查看
一、概述

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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: