本篇为读HenCoder的总结,之后总结会持续跟进,如有错误,请指出
原文链接:http://hencoder.com/ui-1-2/
一、初始化
-
reset()
重置
Paint
的所有属性,相当于重新new
一个 -
set(Paint src)
将一个已有的
src
的所有属性复制过来 -
setFlags(int flags)
批量设置
flags
,eg:mPaint.setFlags(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG); 复制代码
二、颜色相关
回顾一下上期内容,像素的色彩填充具体怎么做?不同的绘制内容有不同的控制方式
canvas.drawColor/RGB/ARGB()
直接绘制颜色;canvas.drawBitmap()
的颜色是由bitmap
的颜色来提供的- 图形和文字,需要
Paint
来设置
1.直接设置颜色
-
setColor(int color)
paint.setColor(Color.parseColor("#009688")); canvas.drawRect(30, 30, 230, 180, paint); paint.setColor(Color.parseColor("#FF9800")); canvas.drawLine(300, 30, 450, 180, paint); paint.setColor(Color.parseColor("#E91E63")); canvas.drawText("HenCoder", 500, 130, paint); 复制代码
-
setARGB
paint.setARGB(100, 255, 0, 0); canvas.drawRect(0, 0, 200, 200, paint); paint.setARGB(100, 0, 0, 0); canvas.drawLine(0, 0, 200, 200, paint); 复制代码
2.setShader(Shader shader)
设置
shader
之后setColor/ARGB
就不管用了首先了解一下着色规则
TileMode
TileMode
一共有 3 个值可选:CLAMP
,MIRROR
和REPEAT
。CLAMP
会在端点之外延续端点处的颜色;MIRROR
是镜像模式;REPEAT
是重复模式。
Shader分类
-
颜色渐变着色器
-
LinearGradient
线性渐变着色器构造方法
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
x0
y0
x1
y1
:渐变的两个端点的位置color0
color1
是端点的颜色tile
:端点范围之外的着色规则
Shader shader = new LinearGradient(100, 100, 500, 500, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP); paint.setShader(shader); ... canvas.drawCircle(300, 300, 200, paint); 复制代码
示例图
-
RadialGradient
辐射渐变着色器构造方法
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)
centerX
centerY
:辐射中心的坐标radius
:辐射半径centerColor
:辐射中心的颜色edgeColor
:辐射边缘的颜色tileMode
:辐射范围之外的着色模式。Shader shader = new RadialGradient(300, 300, 200, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP); paint.setShader(shader); ... canvas.drawCircle(300, 300, 200, paint); 复制代码
示例图
-
SweepGradient
扫描渐变着色器构造方法
SweepGradient(float cx, float cy, int color0, int color1)
cx
cy
:扫描的中心color0
:扫描的起始颜色color1
:扫描的终止颜色Shader shader = new SweepGradient(300, 300, Color.parseColor("#E91E63"), Color.parseColor("#2196F3")); paint.setShader(shader); ... canvas.drawCircle(300, 300, 200, paint); 复制代码
示例图
-
-
BitmapShader
图片着色器用
Bitmap
的像素来作为图形或文字的填充构造方法
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
bitmap
:用来做模板的Bitmap
对象tileX
:横向的TileMode
tileY
:纵向的TileMode
。Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.batman); Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); paint.setShader(shader); ... canvas.drawCircle(300, 300, 200, paint); 复制代码
示例图
-
ComposeShader
混合着色器把两个
Shader
一起使用构造方法
ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
shaderA
,shaderB
:两个相继使用的Shader
mode
: 两个Shader
的叠加模式,即shaderA
和shaderB
应该怎样共同绘制。它的类型是PorterDuff.Mode
。// 第一个 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); ... canvas.drawCircle(300, 300, 300, paint); 复制代码
示例图
PorterDuff.Mode
指定两个图像共同绘制时的策略。官方说明
总共17中,分为两类
Alpha
合成(Alpha
Compositing
)
- 混合(
Blending
)
Alpha
合成比较简单直观,也是需要掌握的,混合模式只需记住就ok。
图解
第一类:Alpha合成
第二类:混合模式Blending
3.setColorFilter(ColorFilter colorfilter)
Paint
除了setColor/ARGB
,setShader
设置颜色外,还可以setColorFilter,对颜色进行过滤
-
LightingColorFilter
模拟简单的光照效果构造方法
LightingColorFilter(int mul, int add)
参数里的
mul
和add
都是和颜色值格式相同的 int 值,其中mul
用来和目标像素相乘,add
用来和目标像素相加公式
R' = R * mul.R / 0xff + add.R G' = G * mul.G / 0xff + add.G B' = B * mul.B / 0xff + add.B 复制代码
示例
//去掉红色 见图左 ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000); paint.setColorFilter(lightingColorFilter); //对应公式 R' = R * 0x0 / 0xff + 0x0 = 0 // 红色被移除 G' = G * 0xff / 0xff + 0x0 = G B' = B * 0xff / 0xff + 0x0 = B //增强绿色 见图右 ColorFilter lightingColorFilter = new LightingColorFilter(0xffffff, 0x003000); paint.setColorFilter(lightingColorFilter); //对应公式 R' = R * 0xff / 0xff + 0x0 = R G' = G * 0xff / 0xff + 0x30 = G + 0x30 // 绿色被加强 B' = B * 0xff / 0xff + 0x0 = B 复制代码
-
PorterDuffColorFilter
使用一个指定的颜色和一种指定
PorterDuff.Mode
与绘制对象进行合成。构造:
PorterDuffColorFilter(int color, PorterDuff.Mode mode)
color
参数是指定的颜色,mode
参数是指定的Mode
-
ColorMatrixColorFilter
使用一个ColorMatrix来对颜色进行处理,ColorMatrix是一个4x5的矩阵
[ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ] 复制代码
转换算法
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; 复制代码
ColorMatrix
有一些自带的方法可以做简单的转换使用
setSaturation(float sat)
来设置饱和度也可以自己去设置它的每一个元素来对转换效果做精细调整
4.setXfermode(Xfermode mode)
Xfermode
是指你要绘制的内容与Canvas
的目标位置的内容应该怎样结合计算出最终的颜色。简单说,以需要绘制的n内容作为源图像,以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
复制代码
注意事项
-
使用离屏缓冲 (
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)
设置填充风格Paint.Style.FILL
填充 默认Paint.Style.STROKE
描边Paint.Style.FILL_AND_STROKE
填充并描边
-
线条形状
-
setStrokeWidth(int width)
设置线条宽度 -
setStrokeCap(Paint.Cap cap)
设置线头的形状BUTT
平头 默认ROUND
圆头SQUARE
方头
-
setStrokeJoin(Paint.Join join)
设置拐角形状MITER
尖角 默认BEVEL
平角ROUND
圆角
-
setStrokeMiter(float miter)
对setStrokeJoin
的补充,设置MITER
形状拐角的最大值
-
-
色彩优化
-
setDither(boolean dither) 设置图像的抖动
把图像从较高色彩深度(即可用的颜色数)向较低色彩深度的区域绘制时,在图像中有意地插入噪点,通过有规律地扰乱图像来让图像对于肉眼更加真实的做法。
paint.setDither(true); 复制代码
-
setFilterBitmap(boolean filter)
设置双线性过滤图像在放大绘制的时候,默认使用的是最近邻插值过滤,这种算法简单,但会出现马赛克现象;而如果开启了双线性过滤,就可以让结果图像显得更加平滑
paint.setFilterBitmap(true); 复制代码
-
-
setPathEffect(PathEffect pathEffect)
给图形轮廓设置效果注意:
PathEffect
在有些情况下不支持硬件加速,需要关闭硬件加速才能正常使用:Canvas.drawLine()
和Canvas.drawLines()
方法画直线时,setPathEffect()
是不支持硬件加速的;PathDashPathEffect
对硬件加速的支持也有问题,所以当使用PathDashPathEffect
的时候,最好也把硬件加速关了。
-
CornerPathEffect
将所有拐角变成圆角PathEffect pathEffect = new CornerPathEffect(20); paint.setPathEffect(pathEffect); ... canvas.drawPath(path, paint); 复制代码
-
DiscretePathEffect
将线条进行随机偏离,让轮廓变得乱七八糟//构造方法 DiscretePathEffect(float segmentLength, float deviation) //segmentLength 是用来拼接的每个线段的长度, deviation 是偏离量。 PathEffect pathEffect = new DiscretePathEffect(20, 5); paint.setPathEffect(pathEffect); ... canvas.drawPath(path, paint); 复制代码
-
DashPathEffect
使用虚线来绘制线条PathEffect pathEffect = new DashPathEffect(new float[]{20, 10, 5, 10}, 0); paint.setPathEffect(pathEffect); ... canvas.drawPath(path, paint); 复制代码
-
PathDashPathEffect
使用Path
绘制虚线Path dashPath = ...; // 使用一个三角形来做 dash PathEffect pathEffect = new PathDashPathEffect(dashPath, 40, 0, PathDashPathEffectStyle.TRANSLATE); paint.setPathEffect(pathEffect); ... canvas.drawPath(path, paint); 复制代码
-
SumPathEffect
同时作用两种PathEffect
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
分别作用两种PathEffectPathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0); PathEffect discreteEffect = new DiscretePathEffect(20, 5); pathEffect = new ComposePathEffect(dashEffect, discreteEffect); ... canvas.drawPath(path, paint); 复制代码
-
setShadowLayer(float radius, float dx, float dy, int shadowColor)
在之后的绘制内容下面加一层阴影。clearShadowLayer()
清楚阴影硬件加速开启的情况下,
setShadowLayer()
只支持文字的绘制,文字之外的绘制必须关闭硬件加速才能正常绘制阴影。如果
shadowColor
是半透明的,阴影的透明度就使用shadowColor
自己的透明度;而如果shadowColor
是不透明的,阴影的透明度就使用paint
的透明度。paint.setShadowLayer(10, 0, 0, Color.RED); ... canvas.drawText(text, 80, 300, paint); 复制代码
-
setMaskFilter(MaskFilter maskFilter)
设置在之后的绘制内容上方的附加效果。-
BlurMaskFilter
模糊效果的MaskFilter
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL)); ... canvas.drawBitmap(bitmap, 100, 100, paint); 复制代码
模糊的类型。一共有四种:
NORMAL
: 内外都模糊绘制SOLID
: 内部正常绘制,外部模糊INNER
: 内部模糊,外部不绘制OUTER
: 内部不绘制,外部模糊
-
EmbossMaskFilter
浮雕效果paint.setMaskFilter(new EmbossMaskFilter(new float[]{0, 1, 1}, 0.2f, 8, 10)); ... canvas.drawBitmap(bitmap, 100, 100, paint); 复制代码
-
-
获取绘制的
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)
-