自定义View Paint 详解-2

2效果

效果类的API,指的就是抗锯齿,填充/轮廓,线条宽度等。

2.1.setAntiAlias(Boolean true) 设置抗锯齿

抗锯齿默认关闭,如果需要抗锯齿,需要手动打开。可以在构造方法中传入Paint.ANIT_ALIAS_FLAG或者通过setAntiAlias(true)来打开


自定义View Paint 详解-2_第1张图片
image.png

2.2.setStyle(Paint.Style Style)

Paint.Style 一共有三种模式:


自定义View Paint 详解-2_第2张图片
image.png

2.3.线条形状

设置线条形状的方法共有4个:
setStrokeWidth(float width),
setStrokeCap(Paint.Cap cap),
setStrokeJoin(Paint.Join join)
setStrokeMiter(float miter)

2.3.1setStrokeWidth(float width)

设置线条宽度,默认为0。


自定义View Paint 详解-2_第3张图片
image.png

扩:

默认情况下,线条宽度为 0,但你会发现,这个时候它依然能够画出线,线条的宽度为 1 像素。那么它和线条宽度为 1 有什么区别:

你可以为 Canvas 设置 Matrix 来实现几何变换(如放大、缩小、平移、旋转),在几何变换之后 Canvas 绘制的内容就会发生相应变化,包括线条也会加粗,例如 2 像素宽度的线条在 Canvas 放大 2 倍后会被以 4 像素宽度来绘制。而当线条宽度被设置为 0 时,它的宽度就被固定为 1 像素,就算 Canvas 通过几何变换被放大,它也依然会被以 1 像素宽度来绘制。Google 在文档中把线条宽度为 0 时称作「hairline mode(发际线模式)」。

2.3.2setStrokeCap(Paint.Cap cap)

设置线头的形状。共有三种类型:BUTT平头,ROUND圆头,SQUARE方头,默认为BUTT平头。


自定义View Paint 详解-2_第4张图片
image.png
注:如果线条的宽度为1像素的时候,这三种状态是一样的。

2.3.3setStrokeJoin(Paint.Join join)

设置拐角的形状。有三种状态:MITER尖角,BEVEL 平角,ROUND圆角。


自定义View Paint 详解-2_第5张图片
image.png

2.3.4setStrokeMiter(float miter)

这个是对于setStrokeJoin(float miter)的补充,他用于设置MITER拐角的延长线的最大值。


自定义View Paint 详解-2_第6张图片
image.png

例外:如果拐角的角度太小,有可能会出现连接点过长的情况。


自定义View Paint 详解-2_第7张图片
image.png

MITER 型连接点有一个额外的规则:当尖角过长时,自动改用 BEVEL 的方式来渲染连接点。


自定义View Paint 详解-2_第8张图片
image.png

2.4 色彩优化

Paint 的色彩优化有两个方法: setDither(boolean dither) 和 setFilterBitmap(boolean filter) 。它们的作用都是让画面颜色变得更加顺眼。

2.4.1 setDither(boolean dither)

设置图像抖动
所谓抖动(注意,它就叫抖动,不是防抖动,也不是去抖动,有些人在翻译的时候自作主张地加了一个「防」字或者「去」字,这是不对的),是指把图像从较高色彩深度(即可用的颜色数)向较低色彩深度的区域绘制时,在图像中有意地插入噪点,通过有规律地扰乱图像来让图像对于肉眼更加真实的做法。

比如向 1 位色彩深度的区域中绘制灰色,由于 1 位深度只包含黑和白两种颜色,在默认情况下,即不加抖动的时候,只能选择向上或向下选择最接近灰色的白色或黑色来绘制,那么显示出来也只能是一片白或者一片黑。而加了抖动后,就可以绘制出让肉眼识别为灰色的效果了:


自定义View Paint 详解-2_第9张图片
image.png

自定义View Paint 详解-2_第10张图片
image.png

不过,抖动可不只可以用在纯色的绘制。在实际的应用场景中,抖动更多的作用是在图像降低色彩深度绘制时,避免出现大片的色带与色块。类似于:


自定义View Paint 详解-2_第11张图片
image.png

在android中使用

PathEffect pathEffect = new DiscretePathEffect(20, 5);  
paint.setPathEffect(pathEffect);
    
...

canvas.drawPath(path, paint); 

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

2.4.2 setDilterBitmap(boolean filter)

设置双线性过滤在绘制Bitmap

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


自定义View Paint 详解-2_第12张图片
image.png

在Android中使用
paint.setFilterBitmap(true);

2.5 setPathEffect(PathEffect effect)

使用 PathEffect 来给图形的轮廓设置效果。对 Canvas 所有的图形绘制有效。

Android 中的 6 种 PathEffect。PathEffect 分为两类,单一效果的 CornerPathEffect DiscretePathEffect DashPathEffect PathDashPathEffect ,和组合效果的 SumPathEffect ComposePathEffect。

2.5.1CornerPathEffect

将所有拐角变成圆角

PathEffect pathEffect = new CornerPathEffect(20);  
paint.setPathEffect(pathEffect);
自定义View Paint 详解-2_第13张图片
image.png
2.5.2DiscretePathEffect

将线条进行随机偏离,让轮廓乱七八糟。乱七八糟的程度由参数决定。

PathEffect pathEffect = new DiscretePathEffect(20, 5);  
paint.setPathEffect(pathEffect);
自定义View Paint 详解-2_第14张图片
image.png

DiscretePathEffect 具体的做法是,把绘制改为使用定长的线段来拼接,并且在拼接的时候对路径进行随机偏离。它的构造方法 DiscretePathEffect(float segmentLength, float deviation) 的两个参数中, segmentLength 是用来拼接的每个线段的长度, deviation 是偏离量。这两个值设置得不一样,显示效果也会不一样。

2.5.3DashPathEffect

使用虚线来绘制线条

PathEffect pathEffect = new DashPathEffect(new float[]{20, 10, 5, 10}, 0);  
paint.setPathEffect(pathEffect);
自定义View Paint 详解-2_第15张图片
image.png

它的构造方法 DashPathEffect(float[] intervals, float phase) 中, 第一个参数 intervals 是一个数组,它指定了虚线的格式:数组中元素必须为偶数(最少是 2 个),按照「画线长度、空白长度、画线长度、空白长度」……的顺序排列,例如上面代码中的 20, 5, 10, 5 就表示虚线是按照「画 20 像素、空 5 像素、画 10 像素、空 5 像素」的模式来绘制;第二个参数 phase 是虚线的偏移量。

2.5.4PathDashPathEffect

使用一个Paht来绘制虚线

Path dashPath = ...; // 使用一个三角形来做 dash  
PathEffect pathEffect = new PathDashPathEffect(dashPath, 40, 0,  
PathDashPathEffectStyle.TRANSLATE);
paint.setPathEffect(pathEffect);
自定义View Paint 详解-2_第16张图片
image.png

构造方法 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:变体

2.5.5SumPathEffect

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

PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);  
PathEffect discreteEffect = new DiscretePathEffect(20, 5);  
pathEffect = new SumPathEffect(dashEffect, discreteEffect);
自定义View Paint 详解-2_第17张图片
image.png
2.5.6ComposePathEffect

它是先对目标 Path 使用一个 PathEffect,然后再对这个改变后的 Path 使用另一个 PathEffect。

PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);  
PathEffect discreteEffect = new DiscretePathEffect(20, 5);  
pathEffect = new ComposePathEffect(dashEffect, discreteEffect);
自定义View Paint 详解-2_第18张图片
image.png

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

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

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

在绘制内容的下面加一层阴影

paint.setMaskFilter(new EmbossMaskFilter(new float[]{0, 1, 1}, 0.2f, 8, 10));

...

canvas.drawBitmap(bitmap, 100, 100, paint); 
image.png

清除阴影:clearShadowLayer();

注:
在硬件加速开启的情况下, setShadowLayer() 只支持文字的绘制,文字之外的绘制必须关闭硬件加速才能正常绘制阴影。
如果 shadowColor 是半透明的,阴影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor 是不透明的,阴影的透明度就使用 paint 的透明度。

2.7 setMaskFilter(MaskFilter maskfilter)

与setShadowLayer()方法相反,setShadowLayer()是在绘制曾下方附加效果。setMaskFilter()是在绘制层上方附加效果。

MaskFilter 共有两种:BluerMaskFilter EmbossMaskFilter

2.7.1 BlurMaskFilter 模糊效果

paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));

自定义View Paint 详解-2_第19张图片
image.png

它的构造方法 BlurMaskFilter(float radius, BlurMaskFilter.Blur style) 中, radius 参数是模糊的范围, style 是模糊的类型。一共有四种:
NORMAL: 内外都模糊绘制
SOLID: 内部正常绘制,外部模糊
INNER: 内部模糊,外部不绘制
OUTER: 内部不绘制,外部模糊

自定义View Paint 详解-2_第20张图片
image.png
2.7.2 EmbossMaskFilter 浮雕效果

paint.setMaskFilter(new EmbossMaskFilter(new float[]{0, 1, 1}, 0.2f, 8, 10));


自定义View Paint 详解-2_第21张图片
image.png

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

2.8 获取绘制的Path

根据Path的位置,计算出绘制Path或文字时的实际Path

2.8.1 getFillPath(Path src,Path dst)

所谓实际 Path ,指的就是 drawPath() 的绘制内容的轮廓,要算上线条宽度和设置的 PathEffect。

默认情况下(线条宽度为 0、没有 PathEffect),原 Path 和实际 Path 是一样的;而在线条宽度不为 0 (并且模式为 STROKE 模式或 FLL_AND_STROKE ),或者设置了 PathEffect 的时候,实际 Path 就和原 Path 不一样了:

自定义View Paint 详解-2_第22张图片
image.png

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

2.8.2 getTextPath(String text, int start, int end, float x, float y, Path path) / getTextPath(char[] text, int index, int count, float x, float y, Path path)

文字的绘制,虽然是使用 Canvas.drawText() 方法,但其实在下层,文字信息全是被转化成图形,对图形进行绘制的。 getTextPath() 方法,获取的就是目标文字所对应的 Path 。


自定义View Paint 详解-2_第23张图片
image.png

你可能感兴趣的:(自定义View Paint 详解-2)