绘制在View.draw()方法里调用的,具体的执行顺序是:
drawBackground():绘制背景,不能重写。
onDraw():绘制主体。
dispatchDraw():绘制子View
onDrawForeground():绘制滑动边缘渐变、滚动条和前景。
我们如果继承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
}
}
在Paint类中,处理颜色主要有三个方法。
着色器是图像领域的一个通用概念,它提供的是一套着色规则。着色器具体由Shader的子类实现。
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);
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);
public BitmapShader(@NonNull Bitmap bitmap, TileMode tileX, TileMode tileY)
参数名 | 参数值 |
---|---|
bitmap | 用来做模板的 Bitmap 对象 |
tileX | 横向的 TileMode |
tileY | 纵向的 TileMode。 |
ComposeShader可以将连个Shader组合在一起
public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
参数名 | 参数值 |
---|---|
shaderA, shaderB | 两个相继使用的 Shader |
mode | 两个 Shader 的叠加模式,即 shaderA 和 shaderB 应该怎样共同绘制。它的类型是PorterDuff.Mode。 |
PorterDuff.Mode用来指定两个Shader叠加时颜色的绘制策略,它有很多种策略,也就是以一种怎样的模式来与原图像进行合成,具体如下
颜色过滤器可以将颜色按照一定的规则输出,常见于各种滤镜效果。
public LightingColorFilter(int mul, int add)
mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加
//颜色过滤器
ColorFilter colorFilter1 = new LightingColorFilter(Color.RED, Color.BLUE);
paint2.setColorFilter(colorFilter1);
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
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;
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) | 设置次像素级抗锯齿,根据程序所运行的设备的屏幕类型,来进行针对性的次像素级的抗锯齿计算,从而达到更好的抗锯齿效果。 |
默认关闭,用来是图像的绘制更加圆润。我们还可以在初始化的时候设置Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);。
设置值 | 解析 |
---|---|
FILL 模式 | 填充 |
STROKE 模式 | 画线 |
FILL_AND_STROKE 模式 | 填充 + 画线 |
如果是划线模式,我们针对线条还可以有多种设置
setStrokeWidth(float width) - 设置线条粗细
setStrokeCap(Paint.Cap cap) - 设置线头的形状,默认为 BUTT
setStrokeJoin(Paint.Join join) - 设置拐角的形状。默认为 MITER
setStrokeMiter(float miter)- 设置 MITER 型拐角的延长线的最大值
图像在放大绘制的时候,默认使用的是最近邻插值过滤,这种算法简单,但会出现马赛克现象;而如果开启了双线性过滤,就可以让结果图像显得更加平滑。
etPathEffect(PathEffect effect)
属性值 | 解说 |
---|---|
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);
处于目标下层图层
参数说明
参数名 | 说明 |
---|---|
float radius | 阴影半径 |
float dx | 阴影偏移量 |
float dy | 阴影偏移量 |
int shadowColor | 阴影颜色 |
设置图层遮罩层,处于目标上层图层。