精通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);

精通Android自定义View(六)绘制篇Paint分析_第1张图片

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);

精通Android自定义View(六)绘制篇Paint分析_第2张图片

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叠加时颜色的绘制策略,它有很多种策略,也就是以一种怎样的模式来与原图像进行合成,具体如下
精通Android自定义View(六)绘制篇Paint分析_第3张图片

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)

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

你可能感兴趣的:(Android自定义View)