android Xfermode PorterDuffXfermode 实现遮罩层
参考:
http://www.cnblogs.com/jacktu/archive/2012/01/02/2310326.html
http://blog.csdn.net/yun90/article/details/8618521
基础知识:
1.下面的Xfermode子类可以改变这种行为:
AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素XOR操作。
PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
要应用转换模式,可以使用setXferMode方法,如下所示:
AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID); borderPen.setXfermode(avoid);
2.Porter-Duff 效果图:
3.16条Porter-Duff规则
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
13.PorterDuff.Mode.DARKEN
14.PorterDuff.Mode.LIGHTEN
15.PorterDuff.Mode.MULTIPLY
16.PorterDuff.Mode.SCREEN
实例1:
首先用图片处理软件制作一个和中间黄色区域相同的图形,我们将在代码中设置它做为遮罩。
mast 图
View的draw方法
只用控制绘制的矩形的长度就可以实现进度条的效果了。
实例2
launcher程序中将icon设置为圆角形状
package com.example.testsurfaceview; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; @SuppressLint("NewApi") public class CustomSurfaceView extends SurfaceView implements Callback { public CustomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } public CustomSurfaceView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public CustomSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CustomSurfaceView(Context context) { super(context); init(); } private void init() { this.getHolder().addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { Canvas canvas = getHolder().lockCanvas(); canvas.drawColor(Color.WHITE); int w = canvas.getWidth(); int h = canvas.getHeight(); Bitmap bitmap = this.getIcon(this.getContext()); Bitmap mat = BitmapFactory.decodeResource(this.getResources(), R.drawable.default_icon_mask); bitmap = this.composeMat(this.getContext(), bitmap, mat); int left = (w - bitmap.getWidth()) / 2; int top = (h - bitmap.getHeight()) / 2; canvas.drawBitmap(bitmap, left, top, new Paint()); getHolder().unlockCanvasAndPost(canvas); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub } private Bitmap getIcon(Context mContext) { int wh = (int) mContext.getResources().getDimension(R.dimen.icon_wh); int width = wh; int height = wh; Drawable icon = mContext.getResources().getDrawable( R.drawable.ic_launcher); if (icon instanceof PaintDrawable) { PaintDrawable painter = (PaintDrawable) icon; painter.setIntrinsicWidth(width); painter.setIntrinsicHeight(height); } else if (icon instanceof BitmapDrawable) { // Ensure the bitmap has a density. BitmapDrawable bitmapDrawable = (BitmapDrawable) icon; Bitmap bitmap = bitmapDrawable.getBitmap(); if (bitmap.getDensity() == Bitmap.DENSITY_NONE) { bitmapDrawable.setTargetDensity(mContext.getResources() .getDisplayMetrics()); } } int sourceWidth = icon.getIntrinsicWidth(); int sourceHeight = icon.getIntrinsicHeight(); if (sourceWidth > 0 && sourceHeight > 0) { // There are intrinsic sizes. if (wh < sourceWidth || wh < sourceHeight) { // It's too big, scale it down. final float ratio = (float) sourceWidth / sourceHeight; if (sourceWidth > sourceHeight) { height = (int) (width / ratio); } else if (sourceHeight > sourceWidth) { width = (int) (height * ratio); } } else if (sourceWidth < width && sourceHeight < height) { // Don't scale up the icon width = sourceWidth; height = sourceHeight; } } int textureWidth = wh; int textureHeight = wh; final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight, Bitmap.Config.ARGB_8888); Canvas sCanvas = new Canvas(); sCanvas.setBitmap(bitmap); sCanvas.drawColor(Color.GRAY); final int left = (textureWidth - width) / 2; final int top = (textureHeight - height) / 2; icon.setBounds(left, top, left + width, top + height); Rect sOldBounds = new Rect(); sOldBounds.set(icon.getBounds()); icon.setBounds(left, top, left + width, top + height); icon.draw(sCanvas); icon.setBounds(sOldBounds); sCanvas.setBitmap(null); return bitmap; } private static final Paint sThemePaint2 = new Paint(); private static final android.graphics.Xfermode Xfermode_DST_IN = new PorterDuffXfermode( Mode.DST_IN); private static final android.graphics.Xfermode Xfermode_SRC_IN = new PorterDuffXfermode( Mode.SRC_IN); private Bitmap composeMat(Context context, Bitmap src, Bitmap mat) { int sIconWidth = mat.getWidth(); int sIconHeight = mat.getHeight(); final Bitmap base = Bitmap.createBitmap(sIconWidth, sIconHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(base); sThemePaint2.setXfermode(null); // canvas.drawRect(new Rect(0, 0, sIconWidth, sIconHeight), sThemePaint2); // sThemePaint2.setXfermode(Xfermode_SRC_IN); canvas.drawBitmap(mat, (sIconWidth-mat.getWidth())/2, (sIconHeight-mat.getHeight())/2, sThemePaint2); sThemePaint2.setXfermode(Xfermode_SRC_IN); canvas.drawBitmap(src, ((sIconWidth-src.getWidth())/2), (sIconHeight-src.getHeight())/2, sThemePaint2); sThemePaint2.setXfermode(null); return base; } }