作者: 夏至 欢迎转载,但保留这段申明
http://blog.csdn.net/u011418943/article/details/79310254
首先,先抛出一张 Google 的示例图,这是一张让人尴尬的效果图:
为啥这么说?
因为这张图为了能够显示 PorterDuff 的效果,代码是做了一些效果的,这就导致了一些小伙伴在写 demo 理解的时候,发现跟 Google 的效果不一致,从而产生疑问,是不是我写错了?哪里不一致呢?比如我写了 SRC_IN 这个模式,按照上面的效果,应该是这样的:
而实际上,却是这样的:
咦,为啥是这样的,我进入的姿势不对?
不要急,这里我想说的是,你没有理解错,只是源码做了处理而已。
1、ApiDemo 的代码
先看一下 ApiDemo 的代码, src 和 dst 是一张图片,而玄机就在这里,首先先看 src(即蓝色的图片)的代码:
// 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(w/3, h/3, w*19/20, h*19/20, p);
return bm;
}
可以看到,虽然设置了 宽 和 高,但是实际canvas在画的时候,却没有填满,而留一段空白区域出来。我们在四周加一个边框,看一下效果:
可以看到,这里留了一大段的空白区域,同理,dst 的图片也是如此:
而 SRC_IN 是两者相较的地方绘制,那么上面这两张图绘制的结果,就只能是这样:
真相终于大白了,原来是这厮
嗯,那么,来一段帮助你理解这些模式的代码,去折腾吧:
public class XfermodeView extends View {
private static final String TAG = "XfermodeView";
private PorterDuffXfermode mPdXfermode; //定义PorterDuffXfermode变量
//定义MODE常量,等下直接改这里即可进行测试
private static PorterDuff.Mode PD_MODE = PorterDuff.Mode.SRC_IN ;
private int mScreenW, mScreenH; //屏幕宽高
private int mWidth = 200; //绘制的图片宽高
private int nHeight = 200;
private Bitmap mSrcBitmap, mDstBitmap; //上层SRC的Bitmap和下层Dst的Bitmap
private Paint mShowpaint;
public XfermodeView(Context context) {
this(context, null);
}
public XfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
mShowpaint = new Paint();
mShowpaint.setStyle(Paint.Style.STROKE);
mShowpaint.setStrokeWidth(2);
mScreenW = ScreenUtil.getScreenW(context);
mScreenH = ScreenUtil.getScreenH(context);
//创建一个PorterDuffXfermode对象
mPdXfermode = new PorterDuffXfermode(PD_MODE);
//实例化两个Bitmap
mSrcBitmap = makeSrc(mWidth, nHeight);
mDstBitmap = makeDst(mWidth, nHeight);
}
public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//定义一个绘制圆形Bitmap的方法,作为dst图
private 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(0xFF26AAD1);
c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);
//画四周的边框线
mShowpaint.setColor(0xFF26AAD1);
c.drawRect(0,0,w,h, mShowpaint);
return bm;
}
//定义一个绘制矩形的Bitmap的方法,作为src图
private 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(0xFFFFCE43);
Log.d(TAG, "zsr --> makeSrc: "+w/3+" "+w*19/20);
c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p);
//画四周的边框线
mShowpaint.setColor(0xFFFFCE43);
mShowpaint.setStyle(Paint.Style.STROKE);
c.drawRect(0,0,w,h,mShowpaint);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setFilterBitmap(false);
paint.setStyle(Paint.Style.FILL);
//绘制SRC上层的矩形Bitmap
canvas.drawBitmap(mSrcBitmap, (mScreenW / 3 - mWidth) / 2, (mScreenH / 2 - nHeight) / 2, paint);
//绘制DST下层的原型Bitmap
canvas.drawBitmap(mDstBitmap, (mScreenW / 3 - mWidth) / 2 + mScreenW / 3, (mScreenH / 2 - nHeight) / 2, paint);
//创建一个图层,在图层上演示图形混合后的效果
int sc = canvas.saveLayer(0, 0, mScreenW, mScreenH, null, Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(mDstBitmap, (mScreenW / 3 - mWidth) / 2 + mScreenW / 3 * 2,
(mScreenH / 2 - nHeight) / 2, paint); //绘制i
//设置Paint的Xfermode
paint.setXfermode(mPdXfermode);
canvas.drawBitmap(mSrcBitmap, (mScreenW / 3 - mWidth) / 2 + mScreenW / 3 * 2,
(mScreenH / 2 - nHeight) / 2, paint);
paint.setXfermode(null);
// 还原画布
canvas.restoreToCount(sc);
/**
* 画图片的边框,便于理解
*/
// src line
int srcleft = (mScreenW / 3 - mWidth) / 2 + mScreenW / 3 * 2;
int srctop = (mScreenH / 2 - nHeight) / 2;
mShowpaint.setColor(0xFFFFCE43);
canvas.drawRect(srcleft,srctop,srcleft + mWidth,srctop+ nHeight,mShowpaint);
// des line,因为位置一样,加4减4,能看出效果
mShowpaint.setColor(0xFF26AAD1);
canvas.drawRect(srcleft + 4,srctop + 4,
srcleft + mWidth - 4,srctop+ nHeight -4 ,mShowpaint);
}
}