Android笔记 自定义View(四):Canvas使用之绘制背景色 您所在的位置:网站首页 书签纯色背景 Android笔记 自定义View(四):Canvas使用之绘制背景色

Android笔记 自定义View(四):Canvas使用之绘制背景色

2023-11-19 10:28| 来源: 网络整理| 查看: 265

前面介绍了Canvas和Paint的相关概念,下面就详细看下它们是怎么使用的

目录

一、绘制背景颜色

1、PorterDuffxfermode、Xfermode和PorterDuff

Xfermode

PorterDuffXfermode

PorterDuff.Mode

二、总结

一、绘制背景颜色

Canvas绘制背景颜色常用有四个方法,具体看下面:

//设置单一颜色为Canvas的背景颜色。 drawColor(int color) /* * 使用指定的颜色和模式填充Canvas。 */ drawColor(int color, PorterDuff.Mode mode) /* * @param * a 在画布上绘制的透明度,取值范围(0..255). * r 在画布上绘制的红色色值,取值范围(0..255). * g 在画布上绘制的绿色色值,取值范围(0..255). * b 在画布上绘制的蓝色色值,取值范围(0..255). * 使用指定的ARGB填充Canvas。 */ drawARGB(int a, int r, int g, int b) /* * @param * r 在画布上绘制的红色色值,取值范围(0..255). * g 在画布上绘制的绿色色值,取值范围(0..255). * b 在画布上绘制的蓝色色值,取值范围(0..255). * 使用指定的RGB颜色,填充Canvas。 */ public void drawRGB (int r, int g, int b)

上面的几个方法都很简单,注释都有说明。这里大坑就是PorterDuff.Mode这个东东,被它坑了很长时间。下面我来说一下自己的了解,不全之处请见谅。

1、PorterDuffxfermode、Xfermode和PorterDuff

查看PorterDuff类的注释文档:

/** *

This class contains the list of alpha compositing and blending modes * that can be passed to {@link PorterDuffXfermode}, a specialized implementation * of {@link Paint}'s {@link Paint#setXfermode(Xfermode) transfer mode}. * All the available modes can be found in the {@link Mode} enum.

*/

PorterDuff是一种图像混合模式。就是将源像素和背景像素的颜色进行混合,最终显示的颜色取决于其RGB颜色分量和Alpha值。它通过Paint的setXfermode(Xfermode) 方法将值传递给PorterDuffXfermode,PorterDuffXfermode是Xfermode的实现类。我们先看相关源码:

/** * 设置或者清除过渡模式 * xfermode 为Null时,恢复默认值 */ public Xfermode setXfermode(Xfermode xfermode) { int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT; int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT; if (newMode != curMode) { nSetXfermode(mNativePaint, newMode); } mXfermode = xfermode; return xfermode; } Xfermode public class Xfermode { static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt; int porterDuffMode = DEFAULT; }

Xfermode主要是保存一个默认的值。它有三个实现类:AvoidXfermode, PixelXorXfermode以及PorterDuffXfermode。前两个类因为不支持硬件加速在API level 16被标记为Deprecated了,用也可以,但是需要关闭硬件加速。那么需要我们深入理解的就是PorterDuffXfermode类。

PorterDuffXfermode public class PorterDuffXfermode extends Xfermode { public PorterDuffXfermode(PorterDuff.Mode mode) { porterDuffMode = mode.nativeInt; } }

它的概念来自于1984年在ACM SIGGRAPH计算机图形学出版物上发表了“Compositing digital images(合成数字图像)”的Tomas Porter和Tom Duff,有兴趣的可以查阅下。在其构造方法里只有一个参数 PorterDuff.Mode,由它来指定图形合成时颜色值的计算方式。在Paint可以通过以下方式定义:

Paint paint = new Paint(); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));

上面的操作实际上就是选择一个PorterDuff.Mode值进行赋值。在自定义View时,当给Paint的Xfermode赋值时,那么使用该Paint时,就使用了该模式。我们往下看:

PorterDuff.Mode

它将所绘制的图形的像素与Canvas中对应位置的像素按照一定规则进行混合,形成新的像素值,从而更新Canvas中最终的像素颜色值。首先我们看一下官方demo里的效果图:

这张图片从一定程度上形象地说明了图形混合的作用,两个图形一圆一方通过一定的计算产生不同的组合效果,在API中Android为我们提供了18种(比上图多了两种ADD和OVERLAY)模式: 

属性说明颜色CLEAR清理相应的颜色[0, 0]SRC显示上层绘制图片[Sa, Sc]DST显示下层绘制图片[Da, Dc]SRC_OVER正常绘制显示,上下层绘制叠盖。(后者覆盖前者)[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc]DST_OVER

上下层都显示。下层居上显示。

[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc]SRC_IN取两层绘制交集。显示上层。[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc]DST_IN取两层绘制交集。显示下层。[Sa * Da, Sa * Dc]SRC_OUT取上层绘制非交集部分。[Sa * (1 - Da), Sc * (1 - Da)]DST_OUT取下层绘制非交集部分。[Da * (1 - Sa), Dc * (1 - Sa)]SRC_ATOP取下层非交集部分与上层交集部分[Da, Sc * Da + (1 - Sa) * Dc]DST_ATOP取上层非交集部分与下层交集部分[Sa, Sa * Dc + Sc * (1 - Da)]XOR异或:去除两图层交集部分[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]DARKEN取两图层全部区域,交集部分颜色加深[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]LIGHTEN取两图层全部,点亮交集部分颜色[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]MULTIPLY取两图层交集部分叠加后颜色[Sa * Da, Sc * Dc]SCREEN取两图层全部区域,交集部分变为透明色[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]ADD Saturate(S + D)OVERLAY Saturate(S + D)

注意:我按照上面的模式设置画笔的时候发现效果跟上面的效果天差地别,后来网上查找资料发现要实现官方demo效果图中的效果,要满足以下几个条件:

https://blog.csdn.net/wingichoy/article/details/50534175

1、关闭硬件加速。(或者设置为:LAYER_TYPE_HARDWARE)

2、只对两个都是bitmap才有效果。且两个bitmap大小尽量一样。

3、背景色为透明色。

仅仅上面几条得出的效果也可能不完全一样,实际效果要根据实际情况来看。下面看一下我自己实现的几种的效果,有兴趣的可以自己实现下。

public class CustomView extends View { Paint mDstPaint,mSrcPaint; Bitmap mSrcBitmap,mDstBitmap; Canvas mSrcCanvas,mDstCanvas; public CustomView(Context context) { this(context,null); } public CustomView(Context context, AttributeSet attrs) { this(context,attrs,0); } public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mDstPaint = new Paint(); mSrcPaint = new Paint(); mDstPaint.setColor(Color.BLUE); mDstPaint.setAntiAlias(true); mSrcPaint.setColor(Color.YELLOW); mSrcPaint.setAntiAlias(true); //开启硬件离屏缓存:解决黑色问题,效率比关闭硬件加速高。暂时没有发现其他影响 setLayerType(LAYER_TYPE_HARDWARE, null); //准备画布 mSrcBitmap = Bitmap.createBitmap(150,150, Bitmap.Config.ARGB_8888); mSrcCanvas = new Canvas(mSrcBitmap); mDstBitmap = Bitmap.createBitmap(150,150, Bitmap.Config.ARGB_8888); mDstCanvas = new Canvas(mDstBitmap); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //dst mDstCanvas.drawRect(50,50,150,150,mDstPaint); mSrcCanvas.drawCircle(50,50,50,mSrcPaint); //准备好两张位图后在设置画笔模式,然后将图片画上去 mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawBitmap(mDstBitmap,0,0,mDstPaint); canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint); } }

 

效果:

                    

二、总结

上面总结一些Canvas绘制背景色的方法,主要是颜色的混合模式使用得当会做出十分酷炫的效果。以一个我自己做的例子作为总结:

java代码:

public class LogoLoadingView extends View { private Paint paint; private Bitmap bitmap; private int currentTop; private RectF rectF; private PorterDuffXfermode xfermode; public LogoLoadingView(Context context) { super(context); init(); } public LogoLoadingView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ setLayerType(LAYER_TYPE_HARDWARE,null); paint=new Paint(); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL); //设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰 paint.setDither(true); //加快显示速度,本设置项依赖于dither和xfermode的设置 paint.setFilterBitmap(true); bitmap= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); xfermode=new PorterDuffXfermode(PorterDuff.Mode.CLEAR); currentTop=bitmap.getHeight(); rectF=new RectF(0,currentTop,bitmap.getWidth(),bitmap.getHeight()); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); rectF.top=currentTop; canvas.drawBitmap(bitmap,0,0,null); paint.setXfermode(xfermode); paint.setColor(Color.RED); canvas.drawRect(rectF,paint); paint.setXfermode(null); if (currentTop>0){ currentTop--; invalidate(); } } }

xml代码:

效果图:

祝:工作顺利!

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有