精通Android自定义View(六)绘制篇Paint分析

绘制在View.draw()方法里调用的,具体的执行顺序是:
drawBackground():绘制背景,不能重写。
onDraw():绘制主体。
dispatchDraw():绘制子View
onDrawForeground():绘制滑动边缘渐变、滚动条和前景。


1 绘制分析

我们如果继承View来实现自定义View。View类的onDraw()是空实现,所以我们的绘制代码写在super.onDraw(canvas)的前面或者后面都没有关系,如下所示:

public class DrawView extends View {
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制代码,写在super.onDraw(canvas)前后均可
    }
}

但是如果我们继承特定的控件,例如TextView。我们就需要去考虑TextView的绘制逻辑。

public class DrawView extends TextView {
    @Override
    protected void onDraw(Canvas canvas) {

        //写在前面,DrawView的绘制会先于TextView的绘制,TextView绘制的内容可以会覆盖DrawView
        super.onDraw(canvas);
        //写在后面,DrawView的绘制会晚于TextView的绘制,DrawView绘制的内容可以会覆盖TextView
    }
}

2 Paint:顾名思义,画笔,通过Paint可以对绘制行为进行控制。

2.1 颜色处理类

在Paint类中,处理颜色主要有三个方法。

  • setShader(Shader shader):用来处理颜色渐变
  • setColorFilter(ColorFilter filter):用来基于颜色进行过滤处理;
  • setXfermode(Xfermode xfermode) 用来处理源图像和 View 已有内容的关系
2.1.1 setShader(Shader shader)

着色器是图像领域的一个通用概念,它提供的是一套着色规则。着色器具体由Shader的子类实现。

2.1.1.1 线性渐变 LinearGradient
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, TileMode tile)

参数解析:x0 y0 x1 y1:渐变的两个端点的位置,color0 color1 是端点的颜色
tile:端点范围之外的着色规则,类型是 TileMode(定义平铺模式)。TileMode 一共有 3 个值可选: CLAMP(复制边缘色彩), MIRROR (在水平和垂直方向上使用交替镜像的方式重复图片的绘制)和 REPEAT(图像平铺)。


//线性渐变 案例

        Shader shader1 = new LinearGradient(0, 150, 200, 150, Color.RED, Color.BLUE, Shader.TileMode.CLAMP);
        mPaint.setShader(shader1);

        Shader shader2 = new LinearGradient(0, 350, 200, 350, Color.RED, Color.BLUE, Shader.TileMode.MIRROR);
        mPaint2.setShader(shader2);

        Shader shader3 = new LinearGradient(0, 750, 200, 750, Color.RED, Color.BLUE, Shader.TileMode.REPEAT);
        mPaint3.setShader(shader3);

        canvas.drawRect(0, 100, 1000, 200, mPaint);
        canvas.drawRect(0, 300, 1000, 600, mPaint2);
        canvas.drawRect(0, 700, 1000, 1000, mPaint3);

在这里插入图片描述

2.1.1.2 SweepGradient - 辐射渐变
public RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, @NonNull TileMode tileMode)

参数解析:

参数名参数值
centerX centerY辐射中心的坐标
radius辐射半径
centerColor辐射中心的颜色
edgeColor辐射边缘的颜色
tileMode辐射范围之外的着色模式
        //辐射渐变
        //(0,100)为辐射中心点坐标,参数200为辐射半径
        Shader shader1 = new RadialGradient(0, 100, 200, Color.RED, Color.BLUE, Shader.TileMode.CLAMP);
        mPaint.setShader(shader1);

        Shader shader2 = new RadialGradient(0, 300, 200, Color.RED, Color.BLUE, Shader.TileMode.MIRROR);
        mPaint2.setShader(shader2);

        Shader shader3 = new RadialGradient(0, 700, 200, Color.RED, Color.BLUE, Shader.TileMode.REPEAT);
        mPaint3.setShader(shader3);

        canvas.drawRect(0, 100, 1000, 200, mPaint);
        canvas.drawRect(0, 300, 1000, 600, mPaint2);
        canvas.drawRect(0, 700, 1000, 1000, mPaint3);

在这里插入图片描述

2.1.1.3 BitmapShader - 位图着色
public BitmapShader(@NonNull Bitmap bitmap, TileMode tileX, TileMode tileY)
参数名参数值
bitmap用来做模板的 Bitmap 对象
tileX横向的 TileMode
tileY纵向的 TileMode。
2.1.1.4 ComposeShader - 组合Shader

ComposeShader可以将连个Shader组合在一起

public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) 
参数名参数值
shaderA, shaderB两个相继使用的 Shader
mode两个 Shader 的叠加模式,即 shaderA 和 shaderB 应该怎样共同绘制。它的类型是PorterDuff.Mode。

PorterDuff.Mode用来指定两个Shader叠加时颜色的绘制策略,它有很多种策略,也就是以一种怎样的模式来与原图像进行合成,具体如下
在这里插入图片描述

2.1.2 setColorFilter(ColorFilter filter)

颜色过滤器可以将颜色按照一定的规则输出,常见于各种滤镜效果。

2.1.2.1 LightingColorFilter - 模拟光照效果
public LightingColorFilter(int mul, int add)

mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加

//颜色过滤器
ColorFilter colorFilter1 = new LightingColorFilter(Color.RED, Color.BLUE);
paint2.setColorFilter(colorFilter1);
2.1.2.2 PorterDuffColorFilter - 模拟颜色混合效果
public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode)

PorterDuffColorFilter指定一种颜色和PorterDuff.Mode来与源图像就行合成,也就是以一种怎样的模式来与原图像进行合成

//我们在使用Xfermode的时候也是使用它的子类PorterDuffXfermode
Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
canvas.drawBitmap(rectBitmap, 0, 0, paint); // 画方  
paint.setXfermode(xfermode); // 设置 Xfermode  
canvas.drawBitmap(circleBitmap, 0, 0, paint); // 画圆  
paint.setXfermode(null); // 用完及时清除 Xfermode  
2.1.2.3 ColorMatrixColorFilter - 颜色矩阵过滤

ColorMatrixColorFilter使用一个颜色矩阵ColorMatrix来对象图像进行处理。

public ColorMatrixColorFilter(ColorMatrix matrix)

ColorMatrix是一个4x5的矩阵

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

通过计算,ColorMatrix可以对要绘制的像素进行转换,如下:

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; 

2.2 文字处理类

Paint里有大量方法来设置文字的绘制属性,事实上文字在Android底层是被当做图片来处理的。

方法解说
setTextSize(float textSize)设置文字大小
setTypeface(Typeface typeface)设置文字字体
setFakeBoldText(boolean fakeBoldText)是否使用伪粗体(并不是提到size,而是在运行时描粗的)
setStrikeThruText(boolean strikeThruText)是否添加删除线
setUnderlineText(boolean underlineText)是否添加下划线
setTextSkewX(float skewX)设置文字倾斜度
setTextScaleX(float scaleX)设置文字横向缩放
setLetterSpacing(float letterSpacing)设置文字间距
setFontFeatureSettings(String settings)使用CSS的font-feature-settings的方式来设置文字。
setTextAlign(Paint.Align align)设置文字对齐方式
setTextLocale(Locale locale)设置文字Local
setHinting(int mode)设置字体Hinting(微调),过向字体中加入 hinting 信息,让矢量字体在尺寸过小的时候得到针对性的修正,从而提高显示效果。
setSubpixelText(boolean subpixelText)设置次像素级抗锯齿,根据程序所运行的设备的屏幕类型,来进行针对性的次像素级的抗锯齿计算,从而达到更好的抗锯齿效果。
2.3 特殊效果类
2.3.1 setAntiAlias (boolean aa)设置抗锯齿

默认关闭,用来是图像的绘制更加圆润。我们还可以在初始化的时候设置Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);。

2.3.2 setStyle(Paint.Style style) 设置填充风格
设置值解析
FILL 模式填充
STROKE 模式画线
FILL_AND_STROKE 模式填充 + 画线

如果是划线模式,我们针对线条还可以有多种设置

  • setStrokeWidth(float width) - 设置线条粗细

  • setStrokeCap(Paint.Cap cap) - 设置线头的形状,默认为 BUTT

    • UTT 平头
    • ROUND 圆头
    • SQUARE 方头
  • setStrokeJoin(Paint.Join join) - 设置拐角的形状。默认为 MITER

    • MITER 尖角
    • BEVEL 平角
    • ROUND 圆角
  • setStrokeMiter(float miter)- 设置 MITER 型拐角的延长线的最大值

2.3.3 setDither(boolean dither) 设置图像的抖动。
2.3.3 setFilterBitmap(boolean filter)设置是否使用双线性过滤来绘制 Bitmap

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

2.3.4 设置图形的轮廓效果。Android有六种PathEffect:
属性值解说
CornerPathEffect将拐角绘制成圆角
DiscretePathEffect将线条进行随机偏离
DashPathEffect绘制虚线
PathDashPathEffect使用指定的Path来绘制虚线
SumPathEffect组合两个PathEffect,叠加应用。
ComposePathEffect组合两个PathEffect,叠加应用。
//图形轮廓效果
//绘制圆角 参数 20 为圆角半径
PathEffect cornerPathEffect = new CornerPathEffect(20);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeWidth(5);
paint1.setPathEffect(cornerPathEffect);

//绘制尖角 float segmentLength:用来拼接每个线段的长度,float deviation:偏离量
PathEffect discretePathEffect = new DiscretePathEffect(20, 5);
paint2.setStyle(Paint.Style.STROKE);
paint2.setStrokeWidth(5);
paint2.setPathEffect(discretePathEffect);

//绘制虚线
//float[] intervals:指定了虚线的格式,数组中元素必须为偶数(最少是 2 个),按照「画线长度、空白长度、画线长度、空白长度」……的顺序排列
float phase:虚线的偏移量
PathEffect dashPathEffect = new DashPathEffect(new float[]{20,10, 5, 10}, 0);
paint3.setStyle(Paint.Style.STROKE);
paint3.setStrokeWidth(5);
paint3.setPathEffect(dashPathEffect);

//使用path来绘制虚线
Path path = new Path();//画一个三角来填充虚线
path.lineTo(40, 40);
path.lineTo(0, 40);
path.close();
PathEffect pathDashPathEffect = new PathDashPathEffect(path, 40, 0, PathDashPathEffect.Style.TRANSLATE);
paint4.setStyle(Paint.Style.STROKE);
paint4.setStrokeWidth(5);
paint4.setPathEffect(pathDashPathEffect);
2.3.5 setShadowLayer(float radius, float dx, float dy, int shadowColor)设置阴影图层

处于目标下层图层
参数说明

参数名说明
float radius阴影半径
float dx阴影偏移量
float dy阴影偏移量
int shadowColor阴影颜色
2.3.6 setMaskFilter(MaskFilter maskfilter)

设置图层遮罩层,处于目标上层图层。

早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页