0
点赞
收藏
分享

微信扫一扫

Android Paint 详细讲解



文章目录

  • 1、简介
  • 2、Paint 类常用方法介绍
  • 1)setColor() 设置颜色
  • 2) setStrokeWidth() 设置宽度
  • 3)setAntiAlias(true) 抗齿距
  • 4) setAlpha() 设置画笔透明度
  • 5)setARGB() 设置透明度 和 颜色
  • 6) setStyle() 设置画笔样式
  • 3、线条样式相关的类
  • 1) setStrokeJoin() 线条连接处样式
  • 2)setStrokeMiter() 斜接模式长度限制
  • 3)、setStrokeCap() 设置线头的模式
  • 4)、setPathEffect()设置所有拐角变成圆角。
  • 5) DashPathEffect()设置线条为虚线
  • 6)、PathDashPathEffect() 使用path 绘制虚线
  • 7) DiscretePathEffect() 设置线条随机偏移
  • 8) SumPathEffect () 两种线条模式都执行
  • 9) 、ComposePathEffect()线条组合模式
  • 4、setShader()Gradient 着色渐变 渲染相关的类
  • 1)LinearGradient 线性渐变
  • 2) 、径向渐变 RadialGradient()
  • 3) 、扫描渐变 SweepGradient()
  • 4)位图渐变 BitmapShader
  • 5)混合 渐变( ComposeShader )
  • 5、颜色效果处理
  • 1) LightingColorFilter 设定 基本色素 黄绿黑
  • 2)、PorterDuffColorFilter 设置颜色 模式运算
  • 3)、ColorMatrixColorFilter 色彩锐度等
  • 4)setXfermode 图片转换模式
  • Xfermode 注意事项
  • 6、色彩优化
  • 1)、setDither(boolean dither) 设置图像抖动
  • 2)、setFilterBitmap(boolean filter) 线性过滤
  • 7、设置阴影或者上层效果
  • 1)、setShadowLayer () 设置阴影
  • 2)setMaskFilter(MaskFilter maskfilter) 绘制层上附件效果
  • 8、获取实际路径
  • 1) getFillPath(Path src, Path dst)
  • 2) getTextPath 获取文本路径


1、简介

在Android 中,2D 的图形绘制一般使用的是 Graphics2D 这个类。
Graphics 类,提供了对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制。它是用于在 Java™ 平台上呈现二维形状、文本和图像的基础类。

自定义View 一般我们需要自己绘制一些图形,这就像画家一样,我们需要画笔和画布。

在Android 中整好有两个这样的类,来方便我们自己创作View.
Paint 类 我们称之为 画笔,为画图的过程中,定义各种参数,比如:颜色、线条样式、图案样式等。
Canvas 类我们定义为画布,主要提供若干方法用于绘制各种颜色图案:点、线、路径等。

我们绘制自定义View的时候,一般先定义Paint ,指定绘图参数,再通过Canvas 进行绘制图形。

自定义 MyView 继承 View

package myapplication.lum.com.myapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class MyView extends View {
    String TAG = "lum_ : ";
    Paint paint;
    public MyView(Context context) {
        super(context);
        Log.i(TAG,"1");
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG,"2");

    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        Log.i(TAG,"3");

    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        Log.i(TAG,"4");
    }

    protected void onDraw(Canvas canvas) {
        //图形绘制
    }

}

布局文件 引用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context=".MainActivity">

<myapplication.lum.com.myapplication.MyView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

</LinearLayout>

2、Paint 类常用方法介绍

Paint 类 主要可以实现 画笔的 颜色、透明度、文本 样式等

1)setColor() 设置颜色

我们可以很简单的知道这是设置 画笔的颜色

paint.setColor(Color.RED);  //设置画笔为红色

2) setStrokeWidth() 设置宽度

设置画笔的宽度

paint.setStrokeWidth(10);//设置画笔宽度 ,单位px

在画笔宽度为 0 的情况下,使用 drawLine 或者使用描边模式(STROKE)也可以绘制出内容。只是绘制出的内容始终是 1 像素,不受画布缩放的影响。该模式被称为hairline mode (发际线模式)。

如果你设置了画笔宽度为 1 像素,那么如果画布放大到 2 倍,1 像素会变成 2 像素。但如果是 0 像素,那么不论画布如何缩放,绘制出来的宽度依旧为 1 像素。

paint.setStrokeWidth(0);//设置画笔宽度0  ,单位px  默认一个像素
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        canvas.scale(10,10); //放大 画布 10倍
        canvas.drawCircle(50,50,20,paint);

并没有改变画笔像素大小

Android   Paint 详细讲解_抗锯齿


更改宽度参数:

paint.setStrokeWidth(1);//设置画笔宽度1  ,单位px
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        canvas.scale(10,10); //放大 画布 10倍
        canvas.drawCircle(50,50,20,paint);

画笔像素被跟随放大:

Android   Paint 详细讲解_参数设置_02

3)setAntiAlias(true) 抗齿距

设置是否开启抗齿距: true 开启;false ,不开启

paint.setAntiAlias(true);//抗锯齿功能

抗锯齿是指在图像中,物体边缘总会或多或少的呈现三角形的锯齿,而抗锯齿就是指对图像边缘进行柔化处理,使图像边缘看起来更平滑,更接近实物的物体。说白了,就是画面你看上去,有一小格一小格的东西。抗拒齿就是画面更加精细。

我们画一条直线 对双数三个方法做一次对比:
自定义MyView 继承View 主要代码列出:

public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG,"2");
        //就是通过修改画笔的一些参数设置
        paint = new Paint(); //新建一个画笔对象
        paint.setAntiAlias(true);//抗锯齿功能 打开
        paint.setColor(Color.RED);  //设置画笔颜色 红色
        paint.setStrokeWidth(10);//设置画笔宽度 10,单位px
    }

    protected void onDraw(Canvas canvas) {
       //画一条直线
        canvas.drawLine(0,0,200,200,paint);
    }

Android   Paint 详细讲解_android_03

修改 paint 参数:

Android   Paint 详细讲解_参数设置_04

public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG,"2");
        //就是通过修改画笔的一些参数设置
        paint = new Paint(); //新建一个画笔对象
        paint.setAntiAlias(false);//抗锯齿功能 关闭
        paint.setColor(Color.BLUE);  //设置画笔颜色  蓝色
        paint.setStrokeWidth(40);//设置画笔宽度 40  ,单位px
    }
    
    protected void onDraw(Canvas canvas) {
       //画一条直线
        canvas.drawLine(0,0,200,200,paint);
    }

截个图给你看看:

Android   Paint 详细讲解_抗锯齿_05

4) setAlpha() 设置画笔透明度

public void setAlpha(int a) {      
    nSetAlpha(mNativePaint, a);    
}

取值范围 0~ 255
0是完全透明,255是完全不透明,数值越大 越不透明

public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG,"2");
        //就是通过修改画笔的一些参数设置
        paint = new Paint(); //新建一个画笔对象
        paint.setAntiAlias(true);//抗锯齿功能
        paint.setStrokeWidth(100);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLACK); //设置 黑色
        paint.setAlpha(255); **//设置255  完全不透明**

    }
    protected void onDraw(Canvas canvas) {
       //画一个圆
        canvas.drawCircle(500, 500,400, paint);//画一个点
    }

Android   Paint 详细讲解_参数设置_06

修改参数:

paint.setAlpha(10); //设置255  完全不透明

Android   Paint 详细讲解_参数设置_07

5)setARGB() 设置透明度 和 颜色

public void setARGB(int a, int r, int g, int b) {
        setColor((a << 24) | (r << 16) | (g << 8) | b);
    }

setARGB 设置有四个参数,取值范围都是 0~255,
argb形式alpha,red,green,blue,
第一个参数 是 透明度的 设置
第二个、第三个、第四个 参数分别的 红绿黄 三个基本色素值,来控制画笔颜色

使用方法基本同上。

paint.setARGB(100,0,0,0);

就是意思 设置 透明度为 100, 000 Android 色度代码 表示黑色 的画笔。

6) setStyle() 设置画笔样式

设置绘制的图形是空心样式还是实心样式,默认为实心样式。

public void setStyle(Style style) {
        nSetStyle(mNativePaint, style.nativeInt);
    }

画笔样式有三种,
Paint.Style.FILL:填充内部
Paint.Style.STROKE :描边
Paint.Style.FILL_AND_STROKE :填充内部和描边

我们画一个圆来给大家展示一下 这几个的区别

public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG,"2");
        //就是通过修改画笔的一些参数设置
        paint = new Paint(); 
        paint.setAntiAlias(true);//抗锯齿功能
        paint.setStrokeWidth(100);//设置画笔宽度 ,单位px

    }
 protected void onDraw(Canvas canvas) {
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.FILL); //设置填充模式
        canvas.drawCircle(500, 500,400, paint);//画一个圆
        }

Android   Paint 详细讲解_参数设置_08

修改一下样式的参数:

paint.setStyle(Paint.Style.STROKE); //描边模式

Android   Paint 详细讲解_android_09


修改一下样式:

paint.setStyle(Paint.Style.FILL_AND_STROKE);  //填充 与 描边模式

Android   Paint 详细讲解_抗锯齿_10

很多人看来
paint.setStyle(Paint.Style.FILL); //设置填充模式
paint.setStyle(Paint.Style.FILL_AND_STROKE); //填充 与 描边模式

看起来没有什么差别。
下面我们把这两种模式放到一起比较:
FILL_AND_STROKE 模式画一个 红色的圆
FILL 模式画一个 蓝色的 透明圆

public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG,"2");
        //就是通过修改画笔的一些参数设置
        paint = new Paint(); //新建一个画笔对象
        paint.setAntiAlias(true);//抗锯齿功能
        paint.setStrokeWidth(100);//设置画笔宽度 ,单位px
    }
    
protected void onDraw(Canvas canvas) {
        paint.setColor(Color.RED); //设置红色
        paint.setStyle(Paint.Style.FILL_AND_STROKE);  //设置 填充 与 描边 样式
        canvas.drawCircle(500, 500,400, paint);//画圆
        paint.reset(); //重置画笔

        paint.setColor(Color.BLUE);  // 蓝色
        paint.setStyle(Paint.Style.FILL); //填充模式
        paint.setAlpha(100); 
        canvas.drawCircle(500, 500,400, paint); //画圆
        }

Android   Paint 详细讲解_android_11

我们看到 虽然 他们的 半径,坐标 都是一样的 ,但是最终显示的大小却不是一样的。

我们 再把 填充模式 和 扫描 模式 放到一起比较就清楚了:
FILL 模式画一个 红色的圆
STROKE 模式画一个 蓝色的 透明圆

public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        Log.i(TAG,"2");
        //就是通过修改画笔的一些参数设置
        paint = new Paint(); //新建一个画笔对象
        paint.setAntiAlias(true);//抗锯齿功能
        paint.setStrokeWidth(100);//设置画笔宽度 ,单位px

    }
    protected void onDraw(Canvas canvas) {
        paint.setColor(Color.RED); //设置红色
        paint.setStyle(Paint.Style.FILL);  //设置 填充
        canvas.drawCircle(500, 500,400, paint);//画圆

        paint.setColor(Color.BLUE);  // 蓝色
        paint.setAlpha(100);
        paint.setStyle(Paint.Style.STROKE); //描边 模式
        canvas.drawCircle(500, 500,400, paint); //画圆

    }

Android   Paint 详细讲解_android_12

因此我们可以看到 ,描边模式 显示出来的 半径 是比填充模式大的,
描边模式/填充与描边模式 实际显示半径 r = 圆半径 + (画笔的宽度 / 2)

3、线条样式相关的类
1) setStrokeJoin() 线条连接处样式

样条连接处的样式有三种:

public static enum Join {
BEVEL,
MITER,
ROUND
}

**当绘图样式为 STROKRE / FILL_AND_STROKE 的时候,**这个方法用于指定线条连接拐角样式:

Android   Paint 详细讲解_参数设置_13

我们代码示例:
Paint 图形样式 设置为 STROKRE,连接处样式 设置为 BEVEL:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLUE);
        
        paint.setStyle(Paint.Style.STROKE); //设置绘图模式 扫描
        paint.setStrokeJoin(Paint.Join.BEVEL); //设置线条闭合模式 BEVEL
        canvas.drawRect(100,100,500,500,paint); //画矩形

        Path path = new Path();  //绘制路径 画一个闭合三角形
        path.moveTo(100,700);
        path.lineTo(300,900);
        path.lineTo(100,1200);
        path.close();
        canvas.drawPath(path,paint);
    }

我们可以看到:

连接处 的样式

Android   Paint 详细讲解_抗锯齿_14


当我们改变参数:

paint.setStrokeJoin(Paint.Join.MITER); //设置线条闭合模式 MITER

Android   Paint 详细讲解_参数设置_15

当我们改变参数:

paint.setStyle(Paint.Style.FILL_AND_STROKE); //设置绘图模式 扫描 FILL_AND_STROKE
    paint.setStrokeJoin(Paint.Join.ROUND); //设置线条闭合模式 MITER

Android   Paint 详细讲解_参数设置_16

2)setStrokeMiter() 斜接模式长度限制

Android 中线段连接方式默认是 MITER,即在拐角处延长外边缘,直到相交位置。

Android   Paint 详细讲解_抗锯齿_17


根据数学原理我们可知,如果夹角足够小,接近于零,那么交点位置就会在延长线上无限远的位置。 为了避免这种情况,如果连接模式为 MITER(尖角),当连接角度小于一定程度时会自动将连接模式转换为 BEVEL(平角)。

那么多大的角度算是比较小呢?根据资料显示,这个角度大约是 28.96°,即 MITER(尖角) 模式下小于该角度的线段连接方式会自动转换为 BEVEL(平角) 模式。

我们代码测试一下:
我们设置 连接模式为 MITER ,但是绘制一个连接角度很小的路径

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);

        paint.setStrokeJoin(Paint.Join.MITER); //设置线条闭合模式 MITER

        Path path = new Path();  //绘制路径 画一个闭合三角形
        path.moveTo(100,700);
        path.lineTo(600,700);
        path.lineTo(100,800);
        path.close();
        canvas.drawPath(path,paint);
    }

我们可以看到 小角度 下,确实是 MITER(尖角) 连接模式 自动转换成了 BEVEL (平角)

这个角度 我们计算可得 角度为 11.31 度

Android   Paint 详细讲解_android_18


这个方法是对于 setStrokeJoin() 的一个补充,它用于设置 MITER 型拐角的延长线的最大值。所谓「延长线的最大值」,是这么一回事:当线条拐角为 MITER 时,拐角处的外缘需要使用延长线来补偿

Android   Paint 详细讲解_参数设置_19

而这种补偿方案会有一个问题:如果拐角的角度太小,就有可能由于出现连接点过长的情况。比如这样:
所以为了避免意料之外的过长的尖角出现, MITER 型连接点有一个额外的规则:当尖角过长时,自动改用 BEVEL 的方式来渲染连接点。例如上图的这个尖角,在默认情况下是不会出现的,而是会由于延长线过长而被转为 BEVEL 型连接点:

Android   Paint 详细讲解_抗锯齿_20


用几何知识很容易得出这个比值的计算公式:如果拐角的大小为 θ ,那么这个比值就等于 1 / sin ( θ / 2 ) 。这个 miter limit 的默认值是 4,对应的是一个大约 29° 的锐角:

Android   Paint 详细讲解_抗锯齿_21

默认情况下,大于这个角的尖角会被保留,而小于这个夹角的就会被「削成平头」

所以设置 这个值 越大,则可以保证越小的角度显示出来尖角。

一般设置的参数值 ,和角度值参照表

Android   Paint 详细讲解_android_22

3)、setStrokeCap() 设置线头的模式

该方法用于设置落笔时的样式,控制我们的画笔在离开画板时留下的最后一点图形,
可选值如下:

public static enum Cap {
BUTT,
ROUND,
SQUARE
}

我们代码展示一下:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(80);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);


        paint.setStrokeCap(Paint.Cap.BUTT);   //设置平头
        canvas.drawLine(300,300,700,300,paint);

        paint.setStrokeCap(Paint.Cap.ROUND); //设置圆头
        canvas.drawLine(300,500,700,500,paint);

        paint.setStrokeCap(Paint.Cap.SQUARE); //设置方头
        canvas.drawLine(300,700,700,700,paint);
    }

Android   Paint 详细讲解_参数设置_23

Android   Paint 详细讲解_android_24

4)、setPathEffect()设置所有拐角变成圆角。

PathEffect pathEffect = new CornerPathEffect(20);  
paint.setPathEffect(pathEffect);

...

canvas.drawPath(path, paint);

Android   Paint 详细讲解_参数设置_25

它的构造方法 CornerPathEffect(float radius) 的参数 radius 是圆角的半径。

CornerPathEffect 也可以让手绘效果更加圆润。

5) DashPathEffect()设置线条为虚线

DashPathEffect 用于实现虚线效果(适用于 STROKE 或 FILL_AND_STROKE 样式)。

// intervals:必须为偶数,用于控制显示和隐藏的长度。
// phase:相位。
DashPathEffect(float intervals[], float phase)

Android   Paint 详细讲解_抗锯齿_26

我们代码测试:

PathEffect pathEffectOne = new DashPathEffect(new float[]{100, 50}, 0);
        paint.setPathEffect(pathEffectOne);
        Path pathOne = new Path();
        pathOne.moveTo(100,50);
        pathOne.lineTo(100,1000);
        canvas.drawPath(pathOne,paint);
      //  canvas.drawLine(100,50,100,1000,paint);

        Path pathTwo = new Path();
        PathEffect pathEffectTwo = new DashPathEffect(new float[]{100, 50},   50);  //偏移量 添加 50 
        paint.setPathEffect(pathEffectTwo);
        pathTwo.moveTo(200,50);
        pathTwo.lineTo(200,1000);
        canvas.drawPath(pathTwo,paint);

Android   Paint 详细讲解_android_27

6)、PathDashPathEffect() 使用path 绘制虚线

它的构造方法 PathDashPathEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style) 中,
shape 参数是用来绘制的 Path ;
advance 是两个相邻的 shape 段之间的间隔,不过注意,这个间隔是两个 shape 段的起点的间隔,而不是前一个的终点和后一个的起点的距离;
phase 和 DashPathEffect 中一样,是虚线的偏移;
最后一个参数 style,是用来指定拐弯改变的时候 shape 的转换方式。
style 的类型为 PathDashPathEffect.Style ,是一个 enum ,具体有三个值:
TRANSLATE:位移
ROTATE:旋转
MORPH:变体

Path dashPath = ...; // 使用一个三角形来做 dash  
PathEffect pathEffect = new PathDashPathEffect(dashPath, 40, 0,  
        PathDashPathEffectStyle.TRANSLATE);
paint.setPathEffect(pathEffect);

...

canvas.drawPath(path, paint);

Android   Paint 详细讲解_抗锯齿_28

更改参数 显示效果:

PathDashPathEffectStyle.TRANSLATE

Android   Paint 详细讲解_抗锯齿_29

7) DiscretePathEffect() 设置线条随机偏移

把线条进行随机的偏离,让轮廓变得乱七八糟。乱七八糟的方式和程度由参数决定。

// segmentLength: 分段长度
// deviation: 偏移距离
DiscretePathEffect(float segmentLength, float deviation);

代码示例:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(10);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);

        canvas.drawLine(100,100,100,1000,paint);

        paint.setPathEffect(new DiscretePathEffect(50,10));

        Path path = new Path();
        path.moveTo(500,100);
        path.lineTo(500,1000);
        canvas.drawPath(path,paint);
        }

Android   Paint 详细讲解_抗锯齿_30

8) SumPathEffect () 两种线条模式都执行

这是一个组合效果类的 PathEffect 。它的行为特别简单,就是分别按照两种 PathEffect 分别对目标进行绘制。

PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);  
PathEffect discreteEffect = new DiscretePathEffect(20, 5);  
PathEffect  pathEffect = new SumPathEffect(dashEffect, discreteEffect);
paint.setPathEffect(pathEffect );

...

canvas.drawPath(path, paint);

同时对直线执行两种模式:

Android   Paint 详细讲解_抗锯齿_31

9) 、ComposePathEffect()线条组合模式

这也是一个组合效果类的 PathEffect 。不过它是先对目标 Path 使用一个 PathEffect,然后再对这个改变后的 Path 使用另一个 PathEffect。

PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);  
PathEffect discreteEffect = new DiscretePathEffect(20, 5);  
PathEffect  pathEffect = new ComposePathEffect(dashEffect, discreteEffect);
paint.setPathEffect(pathEffect );
...

canvas.drawPath(path, paint);

效果展示:

Android   Paint 详细讲解_android_32


它的构造方法 ComposePathEffect(PathEffect outerpe, PathEffect innerpe) 中的两个 PathEffect 参数, innerpe 是先应用的, outerpe 是后应用的。所以上面的代码就是「先偏离,再变虚线」。而如果把两个参数调换,就成了「先变虚线,再偏离」。

注意: PathEffect 在有些情况下不支持硬件加速,需要关闭硬件加速才能正常使用:
Canvas.drawLine() 和 Canvas.drawLines() 方法画直线时,setPathEffect()
是不支持硬件加速的; PathDashPathEffect 对硬件加速的支持也有问题,所以当使用 PathDashPathEffect 的时候,最好也把硬件加速关了。

4、setShader()Gradient 着色渐变 渲染相关的类

Graphics2D 渐变种类有:

线性渐变:LinearGradient
径向渐变:RadialGradient
扫描渐变:SweepGradient
位图渐变:BitmapShader
混合渐变:ComposeShader

线性渐变、径向渐变和扫描渐变属于颜色渐变,指定 2 种或 2 种以上的颜色,根据颜色过渡算法自动计算出中间的过渡颜色,从而形成渐变效果,对于开发人员来说,无需关注中间的渐变颜色。
位图渐变则不再是简单的颜色渐变,而是以图片做为贴片有规律的变化,类似于壁纸平铺。混合渐变则能将多种渐变进行组合,实现更加复杂的渐变效果。

渐变种类 分为三种,我们 以A,B 代编两种颜色:

ABAB 型:A、B 两种颜色重复变化,通过 TileMode 类的 REPEAT 常量来表示; ABBA 型:A、B
两种颜色镜像变化,通过 TileMode 类的 MIRROR 常量来表示; AABB 型:A、B 两种颜色只出现一次,通过 TileMode
类的 CLAMP 常量来表示

如下图展示:

Android   Paint 详细讲解_抗锯齿_33


ABAB 渐变模式

1)LinearGradient 线性渐变

线性渐变是有两个点,不同颜色在渐变的方向与这两个点的连线垂直。

Android   Paint 详细讲解_android_34

public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, TileMode tile)

参数意思:
x0、y0:用于决定线性方向的第一个点的坐标(x0,y0);
x1、y1:用于决定线性方向的第二个点的坐标(x1,y1);
color0:第一种颜色;
color1:第二种颜色;
tile:渐变模式

代码示例:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);

        LinearGradient linearGradient = new LinearGradient(100,100,200,100,
                Color.RED,Color.BLUE,Shader.TileMode.MIRROR) ;  //设置渐变区域 属性 
        paint.setShader(linearGradient); //设置线性渐变
        canvas.drawLine(100,100,800,100,paint); //划线

        linearGradient = new LinearGradient(100,200,800,800,Color.RED,Color.BLUE,Shader.TileMode.CLAMP);
        paint.setShader(linearGradient); //设置线性渐变
        canvas.drawRect(100,200,800,800,paint); //画矩形

    }

Android   Paint 详细讲解_抗锯齿_35


如果两种颜色无法满足绘图需求,LinearGradient 支持三种或者三种以上颜色的渐变,对应

的构造方法如下:

public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[], TileMode
tile)

这是一个功能更加强大的构造方法,我们来看看该构造方法参数的作用:
x0、y0:起始点的坐标
x1、y1:终止点的坐标
colors:多种颜色
positions:颜色的位置(比例)
TileMode:渐变模式

我们代码测试一下:

LinearGradient linearGradient = new LinearGradient(100,100,800,100,
                new int [] {Color.RED,Color.YELLOW,Color.BLUE},new float[]{0,0.5f,1},Shader.TileMode.CLAMP) ;  //设置渐变区域 属性
        paint.setShader(linearGradient); //设置线性渐变
        canvas.drawLine(100,100,800,100,paint); //划线

效果展示:

Android   Paint 详细讲解_抗锯齿_36

参数 colors 和 positions 都是数组,前者用于指定多种颜色,后者用于指定每种颜色的起始比例位置。positions 数组中的元素个数与 colors 要相同

2) 、径向渐变 RadialGradient()

径向渐变是以指定的点为中心,向四周以渐变颜色进行圆周扩散,和线性渐变一样,支持两种或多种颜色。

Android   Paint 详细讲解_参数设置_37

public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile)

该构造方法支持两种颜色,下面是参数的作用:
x、y:中心点坐标
radius:渐变半径
color0:起始颜色
color1:结束颜色
TileMode:渐变模式

public RadialGradient(float x, float y, float radius, int colors[], float positions[], TileModetile)

该构造方法支持 3 种或 3 种以上颜色的渐变,各参数的作用如下:
x、y:中心点坐标
radius:渐变半径
colors:多种颜色
positions:颜色的位置(比例)
TileMode:渐变模式

代码示例:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);

        //两个颜色
        RadialGradient radialGradient = new RadialGradient(400,400,300,Color.RED,Color.BLUE,Shader.TileMode.CLAMP) ;//设置渐变区域 属性
        paint.setShader(radialGradient); //设置线性渐变
        canvas.drawCircle(400,400,300,paint); //划线

        //多种颜色
        radialGradient = new RadialGradient(400,1200,300,
               new int[]{Color.RED,Color.YELLOW,Color.GRAY,Color.BLUE},new float[]{0,0.4f,0.8f,1},Shader.TileMode.CLAMP) ;//设置渐变区域 属性
        paint.setShader(radialGradient); //设置线性渐变
        canvas.drawCircle(400,1200,300,paint); //划线
    }

结果显示:

Android   Paint 详细讲解_android_38

3) 、扫描渐变 SweepGradient()

扫面渐变 ,类似于军事雷达一样,不断围绕圆心扫描。

public SweepGradient(float cx, float cy, int color0, int color1)

支持两种颜色的扫描渐变,参数的作用如下:
cx、cy:圆点坐标;
color0:起始颜色;
color1:结束颜色。

public SweepGradient(float cx, float cy, int colors[], float positions[])

支持多种颜色的扫描渐变,参数的作用如下:
cx、cy:圆点坐标;
colors:多种颜色;
positions:颜色的位置(比例)。

代码示例:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);

        //两个颜色
        SweepGradient sweepGradient = new SweepGradient(400,400,Color.RED,Color.BLUE) ;//设置渐变区域 属性
        paint.setShader(sweepGradient); //设置线性渐变
        canvas.drawCircle(400,400,300,paint); //划线

        //多种颜色
        sweepGradient = new SweepGradient(400,1200,
               new int[]{Color.RED,Color.YELLOW,Color.GRAY,Color.BLUE},null) ;//设置渐变区域 属性 position  设置为 null 则均分
        paint.setShader(sweepGradient); //设置线性渐变
        canvas.drawCircle(400,1200,300,paint); //划线
    }

Android   Paint 详细讲解_参数设置_39

4)位图渐变 BitmapShader

位图渐变其实就是绘制的图形中将指定的位图作为背景。如果图形比位图小,则通过渐变模式进行平铺。
BitmapShader 只有一个构造方法。

public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)

TileMode.CLAMP 模式不平铺,TileMode.REPEAT 模式表示平铺,TileMode.MIRROR 模式也表示平铺,但是交错的位图是彼此的镜像,方向相反。可以同时指定水平和垂直两个方向
的渐变模式。

Shader.TileMode.CLAMP:如果着色器超出原始边界范围,会复制边缘颜色。
Shader.TileMode.MIRROR:横向和纵向的重复着色器的图像,交替镜像图像是相邻的图像总是接合。这个官方的说明可能不太好理解,说白了,就是图像不停翻转来平铺,直到平铺完毕。
Shader.TileMode.REPEAT: 横向和纵向的重复着色器的图像。
一般来说,当Canvas的宽度(高度)小于等于BitmapShader中Bitmap的宽度(高度),我们会使用Shader.TileMode.CLAMP模式,否则我们会使用Shader.TileMode.MIRROR或者Shader.TileMode.REPEAT模式。

代码测试:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.agns); //获取图片资源 转换成bitmap 对象
        BitmapShader bitmapShader = new BitmapShader(bitmap,Shader.TileMode.REPEAT,Shader.TileMode.CLAMP);//设置 x,y  方向格式
        paint.setShader(bitmapShader);
        canvas.drawRect(10,10,800,800,paint);

        bitmapShader = new BitmapShader(bitmap,Shader.TileMode.REPEAT,Shader.TileMode.MIRROR);
        paint.setShader(bitmapShader);
        canvas.drawRect(10,850,800,1600,paint);
    }

}

效果展示:

我们可以看到不同模式显示不同效果

Android   Paint 详细讲解_参数设置_40

5)混合 渐变( ComposeShader )

混合渐变是将两种不同的渐变通过位图运算后得到

ComposeShader 有两个构造方法:
 public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode)
 public ComposeShader(Shader shaderA, Shader shaderB, Mode mode)

其中位图运算有16中之多,我们可以先大概看一下

Android   Paint 详细讲解_android_41

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_2); //获取图片资源 转换成bitmap 对象
        Shader  shader1 = new BitmapShader(bitmap,Shader.TileMode.REPEAT,Shader.TileMode.MIRROR);//设置 x,y  方向格式


        LinearGradient shader2 = new LinearGradient(   //线性渐变
                0,0,500,0,Color.RED,Color.BLUE,Shader.TileMode.MIRROR);

        // ComposeShader:结合两个 Shader
        Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.XOR); //XOR 表示 裁剪shader1 shader2 交集
        paint.setShader(shader);

        canvas.drawRect(0,0,getRight(),getBottom(),paint);
    }

如图所示:

Android   Paint 详细讲解_抗锯齿_42

我们可以看一下各个模式的现象:

Android   Paint 详细讲解_参数设置_43


Android   Paint 详细讲解_android_44

5、颜色效果处理
1) LightingColorFilter 设定 基本色素 黄绿黑

这个 LightingColorFilter 是用来模拟简单的光照效果的。
LightingColorFilter 的构造方法是 LightingColorFilter(int mul, int add),
参数里的 mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加:

R' = R * mul.R / 0xff + add.R  
G' = G * mul.G / 0xff + add.G  
B' = B * mul.B / 0xff + add.B

对于一个颜色我们让其保持原,不改变颜色显示的 参数传递:
mul 为 0xffffff,add 为 0x000000(也就是0),那么对于一个像素,它的计算过程就是:
六位 分别代表基本色素 红绿黑

R' = R * 0xff / 0xff + 0x0 = R // R' = R  
G' = G * 0xff / 0xff + 0x0 = G // G' = G  
B' = B * 0xff / 0xff + 0x0 = B // B' = B

基于这个「基本 LightingColorFilter 」,你就可以修改一下做出其他的 filter。比如,如果你想去掉原像素中的红色,可以把它的 mul 改为 0x00ffff (红色部分为 0 ) ,那么它的计算过程就是:

R' = R * 0x0 / 0xff + 0x0 = 0 // 红色被移除  
G' = G * 0xff / 0xff + 0x0 = G  
B' = B * 0xff / 0xff + 0x0 = B

我们代码展示:

protected void onDraw(Canvas canvas) {
paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.agns); //获取图片资源 转换成bitmap 对象
canvas.drawBitmap(bitmap,200,200,paint);

ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000); //去掉红色
paint.setColorFilter(lightingColorFilter);
canvas.drawBitmap(bitmap,200,600,paint);

}
效果展示:

Android   Paint 详细讲解_参数设置_45


当然我们可以随意的修改颜色的参数,比如让绿色更亮:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.agns); //获取图片资源 转换成bitmap 对象
        canvas.drawBitmap(bitmap,200,200,paint);

        ColorFilter lightingColorFilter = new LightingColorFilter(0xffffff, 0x008800); //绿色更亮
        paint.setColorFilter(lightingColorFilter);
        canvas.drawBitmap(bitmap,200,600,paint);

    }

Android   Paint 详细讲解_抗锯齿_46

2)、PorterDuffColorFilter 设置颜色 模式运算

这个 PorterDuffColorFilter 的作用是使用一个指定的颜色 和 一种指定的 PorterDuff.Mode 来与绘制对象进行合成。
它的构造方法是 PorterDuffColorFilter(int color, PorterDuff.Mode mode)
其中的 color 参数是指定的颜色, mode 参数是指定的 Mode

我们代码测试:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_2); //获取图片资源 转换成bitmap 对象
        canvas.drawBitmap(bitmap,200,200,paint);

        ColorFilter colorFilter = new PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.XOR); //去掉 和 绿色结合的部分
        paint.setColorFilter(colorFilter);
        canvas.drawBitmap(bitmap,200,600,paint);

    }

现象展示:

Android   Paint 详细讲解_参数设置_47

3)、ColorMatrixColorFilter 色彩锐度等

ColorMatrixColorFilter 使用一个 ColorMatrix 来对颜色进行处理。 ColorMatrix 这个类,内部是一个 4x5 的矩阵:

[ a, b, c, d, e,
  f, g, h, i, j,
  k, l, m, n, o,
  p, q, r, s, t ]

它的构造函数:

通过计算, ColorMatrix 可以把要绘制的像素进行转换。对于颜色 [R, G, B, A] ,转换算法是这样的:

R’ = a*R + b*G + c*B + d*A + e;  
G’ = f*R + g*G + h*B + i*A + j;  
B’ = k*R + l*G + m*B + n*A + o;  
A’ = p*R + q*G + r*B + s*A + t;

代码测试:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_2); //获取图片资源 转换成bitmap 对象
        canvas.drawBitmap(bitmap,200,200,paint);
        ColorMatrix colorFilter = new ColorMatrix(new float[]{
                -1f, 0f, 0f, 0f, 255f,
                0f, -1f, 0f, 0f, 255f,
                0f, 0f, -1f, 0f, 255f,
                0f, 0f, 0f, 1f, 0f }); //去掉 和 绿色结合的部分
        paint.setColorFilter(new ColorMatrixColorFilter(colorFilter));
        canvas.drawBitmap(bitmap,200,600,paint);

    }

现象展示:

Android   Paint 详细讲解_参数设置_48

这个主要是对显示的色彩进一步的调节等,

Android   Paint 详细讲解_android_49

4)setXfermode 图片转换模式

“Xfermode” 其实就是“Transfer mode”,Xfermode 指的是 你要绘制的内容 和 canvas 的目标位置的内容应该怎样结合计算出最终的颜色。通俗的讲就是要你以绘制的图形作为源图像,以View中已有的内容做为目标图像,选取一个PorterDuff.Mode 作为绘制内容的颜色处理方案。就像这样:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);


        Bitmap bitmapone = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_2); //获取图片资源 转换成bitmap 对象
        Bitmap bitmapTwo = BitmapFactory.decodeResource(getResources(),R.mipmap.rect_2); //获取图片资源 转换成bitmap 对象

        Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); //取交集,交集样式取决于下层,颜色取决于上层
        int saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(bitmapTwo, 0, 0, paint); 
        paint.setXfermode(xfermode); // 设置 Xfermode
        canvas.drawBitmap(bitmapone, 0, 0, paint); 
        paint.setXfermode(null); // 用完及时清除 Xfermode
        canvas.restoreToCount(saved);

    }

效果显示:

Android   Paint 详细讲解_参数设置_50

Xfermode 注意事项

Xfermode 使用很简单,不过有两点需要注意
使用离屏缓冲(Off-screen Buffer)
我们尝试使用代码直接绘制:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);


        Bitmap bitmapone = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_2); //获取图片资源 转换成bitmap 对象
        Bitmap bitmapTwo = BitmapFactory.decodeResource(getResources(),R.mipmap.rect_2); //获取图片资源 转换成bitmap 对象

        Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.XOR);
      //  int saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(bitmapone, 0, 0, paint); // 画方
        paint.setXfermode(xfermode); // 设置 Xfermode
        canvas.drawBitmap(bitmapTwo, 0, 0, paint); // 画圆
        paint.setXfermode(null); // 用完及时清除 Xfermode
      //  canvas.restoreToCount(saved);

    }

我们看到都是黑色:

Android   Paint 详细讲解_android_51


这是为什么呢:

如下

Android   Paint 详细讲解_android_52


按照逻辑我们会认为,在第二步画圆的时候,跟它共同计算的是第一步绘制的方形。但实际上,却是整个 View 的显示区域都在画圆的时候参与计算,并且 View 自身的底色并不是默认的透明色,而且是遵循一种迷之逻辑,导致不仅绘制的是整个圆的范围,而且在范围之外都变成了黑色。就像这样。

Android   Paint 详细讲解_参数设置_53

这……那可如何是好?

要想使用 setXfermode() 正常绘制,必须使用离屏缓存 (Off-screen Buffer) 把内容绘制在额外的层上,再把绘制好的内容贴回 View 中。也就是这样:

Android   Paint 详细讲解_参数设置_54


通过使用离屏缓冲,把要绘制的内容单独绘制在缓冲层, Xfermode 的使用就不会出现奇怪的结果了。使用离屏缓冲有两种方式:

Canvas.saveLayer()

saveLayer() 可以做短时的离屏缓冲。使用方法很简单,在绘制代码的前后各加一行代码,在绘制之前保存,绘制之后恢复:

int saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);


canvas.drawBitmap(rectBitmap, 0, 0, paint); // 画方
paint.setXfermode(xfermode); // 设置 Xfermode
canvas.drawBitmap(circleBitmap, 0, 0, paint); // 画圆
paint.setXfermode(null); // 用完及时清除 Xfermode


canvas.restoreToCount(saved);

View.setLayerType()

View.setLayerType() 是直接把整个 View 都绘制在离屏缓冲中。 setLayerType(LAYER_TYPE_HARDWARE) 是使用 GPU 来缓冲, setLayerType(LAYER_TYPE_SOFTWARE) 是直接直接用一个 Bitmap 来缓冲。

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(50);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);


        Bitmap bitmapone = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_2); //获取图片资源 转换成bitmap 对象
        Bitmap bitmapTwo = BitmapFactory.decodeResource(getResources(),R.mipmap.rect_2); //获取图片资源 转换成bitmap 对象

        Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
     //   int saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
        this.setLayerType(View.LAYER_TYPE_SOFTWARE, paint); //设置软件缓存区
        canvas.drawBitmap(bitmapTwo, 0, 0, paint); // 蓝色方形 底层
        paint.setXfermode(xfermode); // 设置 Xfermode
        canvas.drawBitmap(bitmapone, 0, 0, paint); // 绿色机器人
        paint.setXfermode(null); // 用完及时清除 Xfermode
       // canvas.restoreToCount(saved);

    }

如果没有特殊需求,可以选用第一种方法 Canvas.saveLayer() 来设置离屏缓冲,以此来获得更高的性能。

6、色彩优化

Paint 的色彩优化有两个方法: setDither(boolean dither) 和 setFilterBitmap(boolean filter) 。它们的作用都是让画面颜色变得更加「顺眼」,但原理和使用场景是不同的。

1)、setDither(boolean dither) 设置图像抖动

在实际的应用场景中,抖动更多的作用是在图像降低色彩深度绘制时,避免出现大片的色带与色块。

Android   Paint 详细讲解_android_55


而且在 Android 里使用起来也很简单,一行代码就搞定:

paint.setDither(true);

setDither(dither) 已经没有当年那么实用了,因为现在的 Android 版本的绘制,默认的色彩深度已经是 32 位的 ARGB_8888 ,效果已经足够清晰了。只有当你向自建的 Bitmap 中绘制,并且选择 16 位色的 ARGB_4444 或者 RGB_565 的时候,开启它才会有比较明显的效果。

2)、setFilterBitmap(boolean filter) 线性过滤

图像在放大绘制的时候,默认使用的是最近邻插值过滤,这种算法简单,但会出现马赛克现象;而如果开启了双线性过滤,就可以让结果图像显得更加平滑。

Android   Paint 详细讲解_android_56


而且它的使用同样也很简单:

paint.setFilterBitmap(true);

加上这一行,在放大绘制 Bitmap 的时候就会使用双线性过滤了。

7、设置阴影或者上层效果
1)、setShadowLayer () 设置阴影

构造函数:

setShadowLayer(float radius, float dx, float dy, int shadowColor)

方法的参数里, radius 是阴影的模糊范围; dx dy 是阴影的偏移量; shadowColor 是阴影的颜色。

代码示例:

protected void onDraw(Canvas canvas) {
       // paint.setStrokeWidth(120);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(100); //设置字体大小
        paint.setShadowLayer(10, 0, 0, Color.BLUE);
        canvas.drawText("这是个测试",100,100,paint);

    }

效果展示:

Android   Paint 详细讲解_android_57


清楚阴影:

paint.clearShadowLayer(); //清楚阴影

在硬件加速开启的情况下, setShadowLayer() 只支持文字的绘制,文字之外的绘制必须关闭硬件加速才能正常绘制阴影。

如果 shadowColor 是半透明的,阴影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor
是不透明的,阴影的透明度就使用 paint 的透明度。

2)setMaskFilter(MaskFilter maskfilter) 绘制层上附件效果

为之后的绘制设置 MaskFilter。上一个方法 setShadowLayer() 是设置的在绘制层下方的附加效果;而这个 MaskFilter 和它相反,设置的是在绘制层上方的附加效果。

到现在已经有两个 setXxxFilter(filter) 了。前面有一个 setColorFilter(filter) ,是对每个像素的颜色进行过滤;而这里的 setMaskFilter(filter) 则是基于整个画面来进行过滤。

MaskFilter 有两种: BlurMaskFilter 和 EmbossMaskFilter。

(1)模糊效果的 MaskFilter。
构造方法:
BlurMaskFilter(float radius, BlurMaskFilter.Blur style)

它有四种选择模式:

NORMAL: 内外都模糊绘制
SOLID: 内部正常绘制,外部模糊
INNER: 内部模糊,外部不绘制
OUTER: 内部不绘制,外部模糊

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(10);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(100);

        this.setLayerType(LAYER_TYPE_SOFTWARE, null);

        Bitmap bitmapone = BitmapFactory.decodeResource(getResources(),R.mipmap.agns); //获取图片资源 转换成bitmap 对象

        BlurMaskFilter blurMaskFilterNORMAL = new BlurMaskFilter(50,BlurMaskFilter.Blur.NORMAL);
        paint.setMaskFilter(blurMaskFilterNORMAL);
        canvas.drawBitmap(bitmapone,50,200,paint);

        BlurMaskFilter blurMaskFilterOUTER = new BlurMaskFilter(50,BlurMaskFilter.Blur.OUTER);
        paint.setMaskFilter(blurMaskFilterOUTER);
        canvas.drawBitmap(bitmapone,550,200,paint);

        BlurMaskFilter blurMaskFilterINNER = new BlurMaskFilter(50,BlurMaskFilter.Blur.INNER);
        paint.setMaskFilter(blurMaskFilterINNER);
        canvas.drawBitmap(bitmapone,50,800,paint);

        BlurMaskFilter blurMaskFilterSOLID = new BlurMaskFilter(50,BlurMaskFilter.Blur.SOLID);
        paint.setMaskFilter(blurMaskFilterSOLID);
        canvas.drawBitmap(bitmapone,550,800,paint);
    }

效果展示:

Android   Paint 详细讲解_android_58


(2)EmbossMaskFilter

EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius) 的参数里, direction 是一个 3 个元素的数组,指定了光源的方向; ambient 是环境光的强度,数值范围是 0 到 1; specular 是炫光的系数; blurRadius 是应用光线的范围。

我们代码测试一下:

protected void onDraw(Canvas canvas) {
        paint.setStrokeWidth(10);//设置画笔宽度 ,单位px
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(100);

        this.setLayerType(LAYER_TYPE_SOFTWARE, null);

        //direction 是一个 3 个元素的数组,指定了光源的方向; ambient 是环境光的强度,数值范围是 0 到 1; specular 是炫光的系数; blurRadius 是应用光线的范围。
        EmbossMaskFilter embossMaskFilter =  new EmbossMaskFilter(new float[]{10, 10, 10}, 0.1f, 5, 5);
        paint.setMaskFilter(embossMaskFilter);
        canvas.drawText("Test",100,700,paint);

类似浮雕 效果:

Android   Paint 详细讲解_android_59

8、获取实际路径
1) getFillPath(Path src, Path dst)

通过 getFillPath(src, dst) 方法就能获取这个实际 Path。方法的参数里,src 是原 Path ,而 dst 就是实际 Path 的保存位置。 getFillPath(src, dst) 会计算出实际 Path,然后把结果保存在 dst 里。

Android   Paint 详细讲解_android_60

2) getTextPath 获取文本路径

getTextPath(String text, int start, int end, float x, float y, Path path)

分别是 文字/ 开始获取位置,结束获取的位置,文字所在的X坐标,文字所在的Y坐标,保存的路径

protected void onDraw(Canvas canvas) {
        String text = "测试文本 Test";
        Paint srcPaint = new Paint();
        srcPaint.setTextSize(100);
        srcPaint.setColor(Color.BLACK);
        srcPaint.setStyle(Paint.Style.STROKE);
        canvas.drawText(text,50,100,srcPaint);
        //获取文本路径
        canvas.translate(0,150);
        Path desPath = new Path();
        Paint desPaint = new Paint();
        desPaint.setTextSize(100);
        desPaint.setColor(Color.BLACK);
        desPaint.setStyle(Paint.Style.STROKE);
        srcPaint.getTextPath(text,0,text.length(),50,100,desPath);
        canvas.drawPath(desPath,desPaint);


    }

待续···

文件参考:
Android Paint的使用详解

安卓自定义View进阶-画笔基础(Paint)

Android关于Paint你所知道的和不知道的一切

HenCoder Android 开发进阶: 自定义 View 1-2 Paint 详解

Android 自定义组件 开发详解 (李赞红)


举报

相关推荐

0 条评论