当前位置:   article > 正文

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

canvas 背景颜色

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

目录

一、绘制背景颜色

1、PorterDuffxfermode、Xfermode和PorterDuff

Xfermode

PorterDuffXfermode

PorterDuff.Mode

二、总结


一、绘制背景颜色

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

  1. //设置单一颜色为Canvas的背景颜色。
  2. drawColor(int color)
  3. /*
  4. * 使用指定的颜色和模式填充Canvas。
  5. */
  6. drawColor(int color, PorterDuff.Mode mode)
  7. /*
  8. * @param
  9. * a 在画布上绘制的透明度,取值范围(0..255).
  10. * r 在画布上绘制的红色色值,取值范围(0..255).
  11. * g 在画布上绘制的绿色色值,取值范围(0..255).
  12. * b 在画布上绘制的蓝色色值,取值范围(0..255).
  13. * 使用指定的ARGB填充Canvas。
  14. */
  15. drawARGB(int a, int r, int g, int b)
  16. /*
  17. * @param
  18. * r 在画布上绘制的红色色值,取值范围(0..255).
  19. * g 在画布上绘制的绿色色值,取值范围(0..255).
  20. * b 在画布上绘制的蓝色色值,取值范围(0..255).
  21. * 使用指定的RGB颜色,填充Canvas。
  22. */
  23. public void drawRGB (int r, int g, int b)

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

1、PorterDuffxfermode、Xfermode和PorterDuff

查看PorterDuff类的注释文档:

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

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

  1. /**
  2. * 设置或者清除过渡模式
  3. * xfermode 为Null时,恢复默认值
  4. */
  5. public Xfermode setXfermode(Xfermode xfermode) {
  6. int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT;
  7. int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT;
  8. if (newMode != curMode) {
  9. nSetXfermode(mNativePaint, newMode);
  10. }
  11. mXfermode = xfermode;
  12. return xfermode;
  13. }

Xfermode

  1. public class Xfermode {
  2. static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt;
  3. int porterDuffMode = DEFAULT;
  4. }

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

PorterDuffXfermode

  1. public class PorterDuffXfermode extends Xfermode {
  2. public PorterDuffXfermode(PorterDuff.Mode mode) {
  3. porterDuffMode = mode.nativeInt;
  4. }
  5. }

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

  1. Paint paint = new Paint();
  2. 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、背景色为透明色。

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

  1. public class CustomView extends View {
  2. Paint mDstPaint,mSrcPaint;
  3. Bitmap mSrcBitmap,mDstBitmap;
  4. Canvas mSrcCanvas,mDstCanvas;
  5. public CustomView(Context context) {
  6. this(context,null);
  7. }
  8. public CustomView(Context context, AttributeSet attrs) {
  9. this(context,attrs,0);
  10. }
  11. public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
  12. super(context, attrs, defStyleAttr);
  13. mDstPaint = new Paint();
  14. mSrcPaint = new Paint();
  15. mDstPaint.setColor(Color.BLUE);
  16. mDstPaint.setAntiAlias(true);
  17. mSrcPaint.setColor(Color.YELLOW);
  18. mSrcPaint.setAntiAlias(true);
  19. //开启硬件离屏缓存:解决黑色问题,效率比关闭硬件加速高。暂时没有发现其他影响
  20. setLayerType(LAYER_TYPE_HARDWARE, null);
  21. //准备画布
  22. mSrcBitmap = Bitmap.createBitmap(150,150, Bitmap.Config.ARGB_8888);
  23. mSrcCanvas = new Canvas(mSrcBitmap);
  24. mDstBitmap = Bitmap.createBitmap(150,150, Bitmap.Config.ARGB_8888);
  25. mDstCanvas = new Canvas(mDstBitmap);
  26. }
  27. @Override
  28. protected void onDraw(Canvas canvas) {
  29. super.onDraw(canvas);
  30. //dst
  31. mDstCanvas.drawRect(50,50,150,150,mDstPaint);
  32. mSrcCanvas.drawCircle(50,50,50,mSrcPaint);
  33. //准备好两张位图后在设置画笔模式,然后将图片画上去
  34. mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
  35. canvas.drawBitmap(mDstBitmap,0,0,mDstPaint);
  36. canvas.drawBitmap(mSrcBitmap,0,0,mSrcPaint);
  37. }
  38. }

 

效果:

                    

二、总结

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

java代码:

  1. public class LogoLoadingView extends View {
  2. private Paint paint;
  3. private Bitmap bitmap;
  4. private int currentTop;
  5. private RectF rectF;
  6. private PorterDuffXfermode xfermode;
  7. public LogoLoadingView(Context context) {
  8. super(context);
  9. init();
  10. }
  11. public LogoLoadingView(Context context, AttributeSet attrs) {
  12. super(context, attrs);
  13. init();
  14. }
  15. private void init(){
  16. setLayerType(LAYER_TYPE_HARDWARE,null);
  17. paint=new Paint();
  18. paint.setAntiAlias(true);
  19. paint.setStyle(Paint.Style.FILL);
  20. //设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
  21. paint.setDither(true);
  22. //加快显示速度,本设置项依赖于dither和xfermode的设置
  23. paint.setFilterBitmap(true);
  24. bitmap= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
  25. xfermode=new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
  26. currentTop=bitmap.getHeight();
  27. rectF=new RectF(0,currentTop,bitmap.getWidth(),bitmap.getHeight());
  28. }
  29. @Override
  30. protected void onDraw(Canvas canvas) {
  31. super.onDraw(canvas);
  32. rectF.top=currentTop;
  33. canvas.drawBitmap(bitmap,0,0,null);
  34. paint.setXfermode(xfermode);
  35. paint.setColor(Color.RED);
  36. canvas.drawRect(rectF,paint);
  37. paint.setXfermode(null);
  38. if (currentTop>0){
  39. currentTop--;
  40. invalidate();
  41. }
  42. }
  43. }

xml代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:background="@color/white"
  8. tools:context=".MainActivity">
  9. <com.wqd.app.view.LogoLoadingView
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"/>
  12. </android.support.constraint.ConstraintLayout>

效果图:

祝:工作顺利!

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/254490?site
推荐阅读
相关标签
  

闽ICP备14008679号