赞
踩
前面介绍了Canvas和Paint的相关概念,下面就详细看下它们是怎么使用的
目录
1、PorterDuffxfermode、Xfermode和PorterDuff
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这个东东,被它坑了很长时间。下面我来说一下自己的了解,不全之处请见谅。
查看PorterDuff类的注释文档:
- /**
- * <p>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.</p>
- */
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;
- }
- public class Xfermode {
- static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt;
- int porterDuffMode = DEFAULT;
- }
Xfermode主要是保存一个默认的值。它有三个实现类:AvoidXfermode, PixelXorXfermode以及PorterDuffXfermode。前两个类因为不支持硬件加速在API level 16被标记为Deprecated了,用也可以,但是需要关闭硬件加速。那么需要我们深入理解的就是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时,就使用了该模式。我们往下看:
它将所绘制的图形的像素与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效果图中的效果,要满足以下几个条件:
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代码:
- <?xml version="1.0" encoding="utf-8"?>
- <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/white"
- tools:context=".MainActivity">
-
- <com.wqd.app.view.LogoLoadingView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- </android.support.constraint.ConstraintLayout>
效果图:
祝:工作顺利!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。