300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Android Paint 进阶之 图层混合模式(Xfermode)

Android Paint 进阶之 图层混合模式(Xfermode)

时间:2021-06-11 01:38:42

相关推荐

Android Paint 进阶之 图层混合模式(Xfermode)

上一节概述了Paint进阶需要掌握的API,这一节针对图层混合模式进行讲解,主要是Xfermode的使用。

1.概念

图层混合模式是将所绘制的像素与canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,最终更新canvas中最终显示的像素值。

2.使用场景

图层混合模式使用的三种场景:poseShader(混合渲染);2.画笔的Paint.setXfermode();3.PorterDuffColorFilter(颜色过滤器)。

3.setXfermode使用

1.图层混合模式使用时必须禁止硬件加速

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

2.离屏绘制

// //离屏绘制int layerId = canvas.saveLayer(0,0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);//......中间进行绘制//canvas.restoreToCount(layerId);

3.绘制

// //目标图canvas.drawBitmap(createRectBitmap(mWidth, mHeight), 0, 0, mPaint);// //设置混合模式mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));// //源图,重叠区域右下角部分canvas.drawBitmap(createCircleBitmap(mWidth, mHeight), 0, 0, mPaint);// //清除混合模式mPaint.setXfermode(null);

完整的XferMode代码:

public class XfermodeView extends View {private Paint mPaint;private int mWidth, mHeight;public XfermodeView(Context context) {this(context, null);}public XfermodeView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {//初始化画笔mPaint = new Paint();mPaint.setColor(Color.RED);mPaint.setStyle(Paint.Style.FILL_AND_STROKE);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight = MeasureSpec.getSize(heightMeasureSpec);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//poseShader//2.画笔Paint.setXfermode()//3.PorterDuffColorFilter//禁止硬件加速setLayerType(View.LAYER_TYPE_SOFTWARE, null);setBackgroundColor(Color.GRAY);// //离屏绘制int layerId = canvas.saveLayer(0,0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);// //目标图Dstcanvas.drawBitmap(createRectBitmap(mWidth, mHeight), 0, 0, mPaint);// //设置混合模式mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));// //源图Src,重叠区域右下角部分canvas.drawBitmap(createCircleBitmap(mWidth, mHeight), 0, 0, mPaint);// //清除混合模式mPaint.setXfermode(null);//canvas.restoreToCount(layerId);}//画矩形Dstpublic Bitmap createRectBitmap(int width, int height) {Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);Paint dstPaint = new Paint(Paint.ANTI_ALIAS_FLAG);dstPaint.setColor(0xFF66AAFF);//蓝色canvas.drawRect(new Rect(width / 20, height / 3, 2 * width / 3, 19 * height / 20), dstPaint);return bitmap;}//画圆srcpublic Bitmap createCircleBitmap(int width, int height) {Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);Paint scrPaint = new Paint(Paint.ANTI_ALIAS_FLAG);scrPaint.setColor(0xFFFFCC44);//黄色canvas.drawCircle(width * 2 / 3, height / 3, height / 4, scrPaint);return bitmap;}}

运行后的效果图:

Xfermode模式

从代码中可以看待现在设置的混合模式为ADD,Xfermode有18种类型,详细的解释见下图

//所绘制不会提交到画布上new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//显示上层绘制的图像new PorterDuffXfermode(PorterDuff.Mode.SRC),//显示下层绘制图像new PorterDuffXfermode(PorterDuff.Mode.DST),//正常绘制显示,上下层绘制叠盖new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//上下层都显示,下层居上显示new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//取两层绘制交集,显示上层new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//取两层绘制交集,显示下层new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//取上层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//取下层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//取上层交集部分与下层非交集部分new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//取下层交集部分与上层非交集部分new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//去除两图层交集部分new PorterDuffXfermode(PorterDuff.Mode.XOR),//取两图层全部区域,交集部分颜色加深new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//取两图层全部区域,交集部分颜色点亮new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//取两图层交集部分,颜色叠加new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//取两图层全部区域,交集部分滤色new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//取两图层全部区域,交集部分饱和度相加new PorterDuffXfermode(PorterDuff.Mode.ADD),//取两图层全部区域,交集部分叠加new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)

18种模式对应的效果图如下所示

上图的实现代码的效果图完整代码如下:

public class XfermodesView extends View {private static int W = 250;private static int H = 250;private static final int ROW_MAX = 4; // number of samples per rowprivate Bitmap mSrcB;private Bitmap mDstB;private Shader mBG;// background checker-board pattern//其中Sa全称为Source alpha表示源图的Alpha通道;Sc全称为Source color表示源图的颜色;Da全称为Destination alpha表示目标图的Alpha通道;Dc全称为Destination color表示目标图的颜色,[...,..]前半部分计算的是结果图像的Alpha通道值,“,”后半部分计算的是结果图像的颜色值。//效果作用于src源图像区域private static final Xfermode[] sModes = {//所绘制不会提交到画布上new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//显示上层绘制的图像new PorterDuffXfermode(PorterDuff.Mode.SRC),//显示下层绘制图像new PorterDuffXfermode(PorterDuff.Mode.DST),//正常绘制显示,上下层绘制叠盖new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//上下层都显示,下层居上显示new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//取两层绘制交集,显示上层new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//取两层绘制交集,显示下层new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//取上层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//取下层绘制非交集部分,交集部分变成透明new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//取上层交集部分与下层非交集部分new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//取下层交集部分与上层非交集部分new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//去除两图层交集部分new PorterDuffXfermode(PorterDuff.Mode.XOR),//取两图层全部区域,交集部分颜色加深new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//取两图层全部区域,交集部分颜色点亮new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//取两图层交集部分,颜色叠加new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//取两图层全部区域,交集部分滤色new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//取两图层全部区域,交集部分饱和度相加new PorterDuffXfermode(PorterDuff.Mode.ADD),//取两图层全部区域,交集部分叠加new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)};private static final String[] sLabels = {"Clear", "Src", "Dst", "SrcOver","DstOver", "SrcIn", "DstIn", "SrcOut","DstOut", "SrcATop", "DstATop", "Xor","Darken", "Lighten", "Multiply", "Screen", "Add","Overlay"};public XfermodesView(Context context) {this(context, null);}public XfermodesView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodesView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);if (windowManager != null) {DisplayMetrics display = new DisplayMetrics();windowManager.getDefaultDisplay().getMetrics(display);W = H = (display.widthPixels - 64) / ROW_MAX; //得到矩形}//1,API 14之后,有些函数不支持硬件加速,需要禁用setLayerType(View.LAYER_TYPE_SOFTWARE, null);mSrcB = makeSrc(W, H);mDstB = makeDst(W, H);//根据width和height创建空位图,然后用指定的颜色数组colors来从左到右从上至下一次填充颜色//make a ckeckerboard patternBitmap bm = Bitmap.createBitmap(new int[]{0xFFFFFFFF, 0xFFCCCCCC, 0xFFCCCCCC, 0xFFFFFFFF}, 2, 2, Bitmap.Config.RGB_565);mBG = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);Matrix m = new Matrix();m.setScale(6, 6);mBG.setLocalMatrix(m);}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawColor(Color.WHITE);Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);labelP.setTextAlign(Paint.Align.CENTER);Paint paint = new Paint();paint.setFilterBitmap(false);canvas.translate(15, 35);int x = 0;int y = 0;for (int i = 0; i < sModes.length; i++) {// draw the borderpaint.setStyle(Paint.Style.STROKE);paint.setShader(null);canvas.drawRect(x - 0.5f, y - 0.5f, x + W + 0.5f, y + H + 0.5f, paint);// draw the checker-board patternpaint.setStyle(Paint.Style.FILL);paint.setShader(mBG);canvas.drawRect(x, y, x + W, y + H, paint);// 使用离屏绘制int sc = canvas.saveLayer(x, y, x + W, y + H, null);canvas.translate(x, y);canvas.drawBitmap(makeDst(2 * W / 3, 2 * H / 3), 0, 0, paint);paint.setXfermode(sModes[i]);canvas.drawBitmap(makeSrc(2 * W / 3, 2 * H / 3), W / 3, H / 3, paint);paint.setXfermode(null);canvas.restoreToCount(sc);// draw the labellabelP.setTextSize(20);canvas.drawText(sLabels[i], x + W / 2, y - labelP.getTextSize() / 2, labelP);x += W + 10;// wrap around when we've drawn enough for one rowif ((i % ROW_MAX) == ROW_MAX - 1) {x = 0;y += H + 30;}}}// create a bitmap with a circle, used for the "dst" image// 画圆一个完成的圆static 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(0xFFFFCC44);//黄色c.drawOval(new RectF(0, 0, w, h), p);return bm;}// 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(0, 0, w * 19 / 20, h * 19 / 20, p);return bm;}}

刮刮卡效果

最后附上一个应用实例,效果图如下

完整代码

public class XfermodeEraserView extends View {private Paint mPaint;private Bitmap mDstBmp, mSrcBmp, mTxtBmp;private Path mPath;public XfermodeEraserView(Context context) {this(context, null);}public XfermodeEraserView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public XfermodeEraserView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {//初始化画笔mPaint = new Paint();mPaint.setColor(Color.RED);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(80);//禁用硬件加速setLayerType(View.LAYER_TYPE_SOFTWARE, null);//初始化图片对象mTxtBmp = BitmapFactory.decodeResource(getResources(), R.drawable.result);mSrcBmp = BitmapFactory.decodeResource(getResources(), R.drawable.eraser);mDstBmp = Bitmap.createBitmap(mSrcBmp.getWidth(), mSrcBmp.getHeight(), Bitmap.Config.ARGB_8888);//路径(贝塞尔曲线)mPath = new Path();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制刮奖结果canvas.drawBitmap(mTxtBmp, 0, 0, mPaint);//使用离屏绘制int layerID = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);//先将路径绘制到 bitmap上Canvas dstCanvas = new Canvas(mDstBmp);dstCanvas.drawPath(mPath, mPaint);//绘制 目标图像canvas.drawBitmap(mDstBmp, 0, 0, mPaint);//设置 模式 为 SRC_OUT, 擦橡皮区域为交集区域需要清掉像素mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));//绘制源图像canvas.drawBitmap(mSrcBmp, 0, 0, mPaint);mPaint.setXfermode(null);canvas.restoreToCount(layerID);}private float mEventX, mEventY;@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mEventX = event.getX();mEventY = event.getY();mPath.moveTo(mEventX, mEventY);break;case MotionEvent.ACTION_MOVE:float endX = (event.getX() - mEventX) / 2 + mEventX;float endY = (event.getY() - mEventY) / 2 + mEventY;//画二阶贝塞尔曲线mPath.quadTo(mEventX, mEventY, endX, endY);mEventX = event.getX();mEventY = event.getY();break;}invalidate();return true; //消费事件}}

Xfermode的使用其实不难,主要是学会灵活使用,最后附上demo:/987570437/PaintDemo

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。