作者: 夏至 歡迎轉載,但保留這段申明
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);
}
}