自定义控件 (?/N) - 颜料 Paint

参考来源

一、颜色

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纵向的规则。

扫描二维码关注公众号,回复: 15261681 查看本文章
混合着色器

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
G' = G * mul.G / 0xff + add.G
B' = B * mul.B / 0xff + add.B

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
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.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( )

猜你喜欢

转载自blog.csdn.net/HugMua/article/details/130478049
今日推荐