参考来源
一、颜色
1.1 直接设置颜色
1.1.1 setColor( )
public void setColor(@ColorInt int color) |
paint.setColor(Color.RED)
paint.setColor(Color.parseColor("#009688"))
1.1.2 setARGB( )
public void setARGB(int a, int r, int g, int b) |
paint.setARGB(100, 255, 43, 1)
1.2 设置着色器 setShader( )
Shader 着色器,设置的是一个颜色规则。使用着色器后直接设置颜色的两种方式 setColor( ) 和 setARGB( ) 就不再起作用。
public Shader setShader(Shader shader) |
tile是端点范围之外的着色模式,CLAMP会在端点之外散开端点处颜色、MIRROR镜像、REPEAT重复。 | |
线性渐变 | public LinearGradient(float x0, float y0, float x1, float y1, @ColorInt int color0, @ColorInt int color1, @NonNull TileMode tile) 设置两个点和两种颜色,以这两个点为端点,使用两种颜色的渐变来绘制颜色。 |
辐射渐变 | RadialGradient(float centerX, float centerY, float radius, @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode) centerX,centerY辐射中心坐标、radius辐射半径、centerColor中心颜色、edgeColor边缘颜色、辐射范围之外的着色模式。 |
扫描渐变 | public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1) cx,cy中心点坐标、color0起始颜色、color1终止颜色。 |
Bitmap着色器 | public BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY) tileX 横向的规则、tileY纵向的规则。 |
混合着色器 | public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull PorterDuff.Mode mode) shaderA,shaderB 需要混合使用的两个着色器、mode 叠加模式即如何共同绘制。 |
1.2.1 线性渐变 LinearGradient
val shader = LinearGradient(100F, 100F, 500F, 500F, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP)
paint.setShader(shader)
1.2.2 辐射渐变 RadialGradient
val shader = RadialGradient(300F, 200F, 200F, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP)
paint.setShader(shader)
1.2.3 扫描渐变 SeepGradient
val shader = SweepGradient(300F, 300F, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"))
paint.setShader(shader)
1.2.4 Bitmap着色器 BitmapShader
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.betman)
val shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
paint.setShader(shader)
如果想绘制圆形的 Bitmap 就别用 drawBitmap() 改用 drawCircle()+BitmapShader 就行,其他形状同理。
1.2.5 组合着色器 ComposeShader
PorterDuff.Mode 用来指定两个图像共同绘制时的颜色策略(确定两者叠加后的颜色)。可以分为两类:一类是Alpah合成,共12种,都是关于aplha通道(透明度)计算的,PorterDuff是两个共同发表算法论文人的姓。另一类是混合,Photoshop等制图软件里都有的那些模式,为了方便也被加了进来。
Alpha合成
混合
val bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.betman)
val shader1 = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val bitmap2 = BitmapFactory.decodeResource(resources, R.drawable.logo)
val shader2 = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val shader3 = ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER)
paint.setShader(shader3)
1.3 设置颜色过滤 setColorFilter( )
为绘制的内容设置统一的过滤策略,Canvas.drawXXX()会对每个像素进行过滤后再绘制出来。
public ColorFilter setColorFilter(ColorFilter filter) 使用的是 ColorFilter的 三个子类,见下表。 |
LightingColorFilter | public LightingColorFilter(@ColorInt int mul, @ColorInt int add) 模拟简单光照效果。mul用来和目标像素相乘,add用来和目标像素相加,算法: R' = R * mul.R / 0xff + add.R |
PorterDuffColorFilter | public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) 使用一个指定颜色和一个指定 PorterDuff 模式来与绘制对象进行合成。color指定的颜色、mode指定的模式。(与ComposeShader不同的是只能指定颜色而不是Bitmap) |
ColorMatrixColorFilter | public ColorMatrixColorFilter(@NonNull ColorMatrix matrix) 使用颜色矩阵对颜色进行处理。算法: R' = a * R + b * G + c * B + d * A + e |
paint.colorFilter = LightingColorFilter(0x123456,0xABCDEF)
// R' = R * 0x12 / 0xff + 0xAB
// G' = G * 0x34 / 0xff + 0xCD
// B' = B * 0x56 / 0xff + 0xEF
LightingColorFilter(0x00ffff, 0x000000) //去掉红色
// R' = R * 0x0 / 0xff + 0x0 = 0
LightingColorFilter(0xffffff, 0x003000) //绿色加强
// G' = G * 0xff / 0xff + 0x30 = G + 0x30
1.4 setXfermode( )
要绘制的内容作为源图像,View中已有的内容作为目标图像,指定一个 PorterDuff.Mode 作为绘制内容的颜色处理方案。
public Xfermode setXfermode(Xfermode xfermode) 其它子类已过时,目前只剩下PorterDuffXfermode。 |
1.4.1 使用离屏缓存 Off-screen Buffer
val xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
...
canvas.drawBitmap(rectBitmap, 0F, 0F, paint) //画方
paint.xfermode = xfermode
canvas.drawBitmap(CircleBitmap, 0F, 0F, paint) //画圆
paint.xfermode = null //用完及时清除
在第二步画圆的时候,跟它共同计算的是第一步绘制的方形。但实际上,却是整个 View 的显示区域都在画圆的时候参与计算,并且 View 自身的底色并不是默认的透明色,而且是遵循一种迷之逻辑,导致不仅绘制的是整个圆的范围,而且在范围之外都变成了黑色。 通过使用离屏缓冲,把要绘制的内容单独绘制在缓冲层, Xfermode 的使用就不会出现奇怪的结果了。
Canvas.saveLayer( )
做短时的离屏缓存。在绘制代码的前后各加一行代码:在绘制之前保存,绘制之后恢复。
val xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
val saveLayer = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG) //保存
canvas.drawBitmap(rectBitmap, 0F, 0F, paint)
paint.xfermode = xfermode
canvas.drawBitmap(CircleBitmap, 0F, 0F, paint)
paint.xfermode = null
canvas.restoreToCount(saveLayer) //恢复
View.setLayerType( )
直接把整个 View 都绘制在离屏缓存中。setLayerType(LAYER_TYPE_HARDWARE) 是使用GPU缓存,setLayerType(LAYER_TYPE_SOFTWARE) 是直接用一个Bitmap缓存。无特殊要求使用上面的 Canvas.saveLayer( ) 以获取更好性能。
1.4.2 控制好透明区域
除了使用离屏缓存,还要控制透明区域不能太小,须足够覆盖要结合绘制的内容。如下图透明区域过小而覆盖不到的地方,将不会受到 Xfermode 的影响。
二、效果
2.1 抗锯齿 setAntiAlias( )
public void setAntiAlias(boolean aa) 默认是关闭的,开启后让图形或文字的边缘更加平滑(修改图形边缘处的像素颜色使之肉眼看起来更加平滑的感觉)。推荐通过 Paint 的构造设置更便捷。 |
val paint = Paint(Paint.ANTI_ALIAS_FLAG) //二选一,更推荐
paint.isAntiAlias = true
2.2 绘制风格 setStyle( )
public void setStyle(Style style) //FILL填充、STROKE画线、FILL_AND_STROKE既画线又填充。 |
paint.style = Paint.Style.FILL
2.3 线条形状
线条宽度 | public void setStrokeWidth(float width) 单位为像素,默认0。0和1的区别见下方几何变换。 |
线头形状 | public void setStrokeCap(Cap cap) 默认BUTT平头、ROUND圆头、SQUARE方头。 |
拐角形状 | public void setStrokeJoin(Join join) 默认MITER尖角、 BEVEL平角、ROUND圆角。 |
尖角拐角延长线最大值 | public void setStrokeMiter(float miter) 当拐角形状是MITER尖角时,拐角处的边缘需要使用延长线来补偿。 |
2.3.1 setTtrokeWidth( )
paint.strokeWidth = 3F
2.3.2 setStrokeCap( )
paint.strokeCap = Paint.Cap.ROUND
2.3.3 setStrokeJoin( )
paint.strokeJoin = Paint.Join.BEVEL
2.3.4 setStrokeMiter( )