自定义view1-2 Paint 详解

Paint 的API可以大致分为4类
* 颜色
* 效果
* drawText()相关
* 初始化

颜色

  1. Canvas.drawColor/ARGB() ------ 颜色参数
  2. Canvas.drawBitmap() ------ bitmap 参数
  3. Canvas 图像和文字绘制 ------ paint 参数
基本颜色

paint 设置颜色的方法
1. 直接用Paint.setColor/ARGB() 来设置颜色
2. 使用 Shader 来指定着色方案

setARGB(int a,int r,int g,int b)
通过三原色和透明度设置

setShader(Shader shader) 设置 Shader
子类
LinearGradient
RadialGradient
SweepGradient
BitmapShader
ComposeShader

LinearGradient 线性渐变

设置两个点和两种颜色,以这两个点作为端点,使用两种颜色的渐变来绘制颜色
eg:

Shader shader = new LinearGradient(100, 100, 500, 500, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
paint.setShader(shader);

在设置Shader的情况下,Paint.setColor/ARGB() 所设置的颜色就不再起作用
构造方法
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile) 。
x0 y0 x1 y1:渐变的两个端点的位置
color0 color1 是端点的颜色
tile:端点范围之外的着色规则,类型是 TileMode
TilMode 可选值
CLAMP 会在端点之外延续端点处的颜色
MIRROR 镜像模式
REPEAT 重复模式

RadialGradient 辐射渐变

辐射渐变很好理解,就是从中心向周围辐射状的渐变

Shader shader = new RadialGradient(300, 300, 200, Color.parseColor("#E91E63"),Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
paint.setShader(shader);

构造方法
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)。
参数:
centerX centerY:辐射中心的坐标
radius:辐射半径
centerColor:辐射中心的颜色
edgeColor:辐射边缘的颜色
tileMode:辐射范围之外的着色模式。

SweepGradient 扫描渐变
Shader shader = new SweepGradient(300, 300, Color.parseColor("#E91E63"),Color.parseColor("#2196F3"));
paint.setShader(shader);

构造方法
SweepGradient(float cx, float cy, int color0, int color1)
参数
cx cy :扫描的中心
color0:扫描的起始颜色
color1:扫描的终止颜色

BitmapShader
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.batman);  Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);  
paint.setShader(shader);

构造方法
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
参数
bitmap:用来做模板的 Bitmap 对象
tileX:横向的 TileMode
tileY:纵向的 TileMode。

ComposeShader 混合着色器
// 第一个 Shader:头像的 Bitmap
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.batman);  
Shader shader1 = new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

// 第二个 Shader:从上到下的线性渐变(由透明到黑色)
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.batman_logo);  
Shader shader2 = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

// ComposeShader:结合两个 Shader
Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER);  
paint.setShader(shader);

构造方法
ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
参数
shaderA, shaderB:两个相继使用的 Shader
mode: 两个 Shader 的叠加模式,即 shaderA 和 shaderB 应该怎样共同绘制。它的类型是 PorterDuff.Mode 。
mode:
SRC_OVER
DST_OUT 挖空效果
DST_IN 抠图效果
Alpha 合成 (Alpha Compositing)
混合 (Blending)

setColorFilter(ColorFilter colorFilter)

为绘制设置颜色过滤
子类:
LightingColorFilter
PorterDuffColorFilter
ColorMatrixColorFilter

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

ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);  
paint.setColorFilter(lightingColorFilter);  

增强路颜色

ColorFilter lightingColorFilter = new LightingColorFilter(0xffffff, 0x003000);  
paint.setColorFilter(lightingColorFilter); 

0xffffff
ff/ff/ff 代表红/绿/蓝
0x000000
00/00/00 代表红/绿/蓝

PorterDuffColorFilter

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

ColorMatrixColorFilter

使用一个 ColorMatrix 来对颜色进行处理
setSaturation(float sat) 来设置饱和度

setXfermode(Xfermode xfermode)

以绘制的内容作为源图像,以 View 中已有的内容作为目标图像,选取一个 PorterDuff.Mode 作为绘制内容的颜色处理方案

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  

Xfermode 注意事项

使用离屏缓冲(Off-screen Buffer)
* 方式 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 来缓冲。

控制好透明区域

效果

setAntiAlias (boolean aa) 设置抗锯齿
setStyle(Paint.Style style) 设置图形是线条风格还是填充风格
线条形状

设置线条形状的一共有 4 个方法:setStrokeWidth(float width), setStrokeCap(Paint.Cap cap), setStrokeJoin(Paint.Join join), setStrokeMiter(float miter) 。
setStrokeWidth(float width)
设置线条宽度。单位为像素,默认值是 0。

paint.setStyle(Paint.Style.STROKE);  
paint.setStrokeWidth(1);  
canvas.drawCircle(150, 125, 100, paint);  
paint.setStrokeWidth(5);  
canvas.drawCircle(400, 125, 100, paint);  
paint.setStrokeWidth(40);  
canvas.drawCircle(650, 125, 100, paint);  

setStrokeCap(Paint.Cap cap)
setStrokeJoin(Paint.Join join)
设置拐角的形状。有三个值可以选择:MITER 尖角、 BEVEL 平角和 ROUND 圆角。默认为 MITER。
setStrokeMiter(float miter)
是对于 setStrokeJoin() 的一个补充,设置 MITER 型拐角的延长线的最大值。

色彩优化

setDither(boolean dither)
setFilterBitmap(boolean filter)

setDither(boolean dither)

设置图像的抖动。

paint.setDither(true);
setFilterBitmap(boolean filter)

设置是否使用双线性过滤来绘制 Bitmap

paint.setFilterBitmap(true);

setDither(dither) ,设置抖动来优化色彩深度降低时的绘制效果; setFilterBitmap(filterBitmap) ,设置双线性过滤来优化 Bitmap 放大绘制的效果

setPathEffect(PathEffect effect)

用 PathEffect 来给图形的轮廓设置效果

PathEffect pathEffect = new DashPathEffect(new float[]{10, 5}, 10);  
paint.setPathEffect(pathEffect);

单一效果
CornerPathEffect
DiscretePathEffect
DashPathEffect
PathDashPathEffect
组合效果
SumPathEffect ComposePathEffect。

CornerPathEffect

把所有拐角变成圆角

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

canvas.drawPath(path, paint); 

CornerPathEffect(float radius) 的参数 radius 是圆角的半径

DiscretePathEffect

把线条进行随机的偏离,让轮廓变得乱七八糟

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

...

canvas.drawPath(path, paint); 

DiscretePathEffect(float segmentLength, float deviation) 的两个参数中, segmentLength 是用来拼接的每个线段的长度, deviation 是偏离量。

DashPathEffect

使用虚线来绘制线条

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

...

canvas.drawPath(path, paint);

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

PathDashPathEffect

使用一个 Path 来绘制「虚线」

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

...

canvas.drawPath(path, paint);  

PathDashPathEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style) 中, shape 参数是用来绘制的 Path ; advance 是两个相邻的 shape 段之间的间隔,不过注意,这个间隔是两个 shape 段的起点的间隔,而不是前一个的终点和后一个的起点的距离; phase 和 DashPathEffect 中一样,是虚线的偏移;最后一个参数 style,是用来指定拐弯改变的时候 shape 的转换方式
style: TRANSLATE:位移 ROTATE:旋转 MORPH:变体
##### SumPathEffect
合效果类的 PathEffect
```java
PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);
PathEffect discreteEffect = new DiscretePathEffect(20, 5);
pathEffect = new SumPathEffect(dashEffect, discreteEffect);

...

canvas.drawPath(path, paint);

##### ComposePathEffect
也是一个组合效果类的 PathEffect 。不过它是先对目标 Path 使用一个 PathEffect,然后再对这个改变后的 Path 使用另一个 PathEffect。
```java
PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);  
PathEffect discreteEffect = new DiscretePathEffect(20, 5);  
pathEffect = new ComposePathEffect(dashEffect, discreteEffect);

...

canvas.drawPath(path, paint); 

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

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

绘制内容下面加一层阴影

paint.setShadowLayer(10, 0, 0, Color.RED);

radius 是阴影的模糊范围; dx dy 是阴影的偏移量; shadowColor 是阴影的颜色。
清除阴影层,使用 clearShadowLayer()

setMaskFilter(MaskFilter maskfilter)

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

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

...

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

BlurMaskFilter(float radius, BlurMaskFilter.Blur style) 中, radius 参数是模糊的范围, style 是模糊的类型
* NORMAL: 内外都模糊绘制
* SOLID: 内部正常绘制,外部模糊
* INNER: 内部模糊,外部不绘制
* OUTER: 内部不绘制,外部模糊(什么鬼?)

EmbossMaskFilter

浮雕效果的 MaskFilter。

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

...

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

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

获取绘制的 Path

getFillPath(Path src, Path dst)
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)

文字的 Path

初始化类

reset()

重置 Paint 的所有属性为默认值。相当于重新 new 一个,不过性能当然高一些啦。

set(Paint src)

把 src 的所有属性全部复制过来。相当于调用 src 所有的 get 方法,然后调用这个 Paint 的对应的 set 方法来设置它们。

setFlags(int flags)

批量设置 flags。相当于依次调用它们的 set 方法。
eg:

paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);  

发表评论

电子邮件地址不会被公开。 必填项已用*标注