自定义View1-2 Paint详解

1颜色

Canvas绘制的内容,有三层对颜色的处理:

  • 基本颜色:1、Canvas.drawColor/ARGB() –颜色参数 2、Canvas.drawBitmap()–bitmap参数 3、Canvas图形和文字绘制–paint参数。
  • ColorFilter:Paiint.setColorFilter(CorlorFilter)。
  • Xfermode:Paint.setXfermode(Xfermode)。

1.1 基本颜色

像素的基本颜色,根据绘制内容的不同而有不同的控制方式:

Canvas的颜色填充类方法drawColor/RBG/ARGB() 直接作为参数传入。

drawBitmap()的颜色与bitmap参数的像素颜色相同。

图形和文字(drawCircle()/drawPath()/drawText()…) 在paint参数中设置。

Paint设置颜色的方法有两种:一种是直接用 Paint.setColor/ARGB() 来设置颜色,另一种是使用 shader 来指定着色方案。

1.1.1 直接设置颜色

1.1.1.1 setColor(int color)

paint.color = Color.parseColor("#009688")
canvas.drawRect(30f, 30f, 230f, 180f, paint)

paint.color = Color.parseColor("FF9800")
canvas.drawLine(300f, 30f, 450f, 180f, paint)

paint.color = Color.parseColor("E91E63")
canvas.drawText("HenCoder", 500f, 130f, paint)

1.1.1.2 setARGB(int a, int r, int g, int b)

和setColor(color)一样。

paint.setARGB(100, 255, 0, 0)
canvas.drawRect(0f, 0f, 200f, 200f, paint)
paint.setARGB(100, 0, 0, 0)
canvas.drawLine(0f, 0f, 200f, 200f, paint)

1.1.2setShader(Shader shader) 设置 Shader

除了直接设置颜色,Paint还可以使用Shader。

Shader的中文叫做着色器,它设置的是一个着色方案,当设置了Shader之后,Paint在绘制图形和文字时就不使用setColor/ARGB()设置的颜色了,而是使用Shader的方案中的颜色。

在Android的绘制里使用的Shader,并不是直接用Shader这个类,而是用它的几个子类。具体来讲有LinearGradient、RadialGradient、SweepGradient、BitmapShae、ComposeShader这几个:

1.1.2.1 LinearGradient 线性渐变

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

val shder = LinerGradient(100f, 100f, 500f, 500f, Color.parseColor("#E91E63"),
Color.parseColor("#2196F3"), Shader.TileMode.CLAMP)
paint.shader = shader
canvas.drawCircle(300f, 300f, 200f, paint)

其他形状以及文字都可以这样设置颜色

注意:在设置了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。TileMode一共有三个值可选: CLAMP, MIRROR和REREAT

1.1.2.2 RadialGradient辐射渐变

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

val shader = RadialGradient(300f, 300f, 200f, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shaer.TIleMode.CLAMP)
paint.shader = shader
canvas.drawCircle(300f, 300f, 200f, paint)

构造方法:

RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)

参数:

centerX, centerY: 辐射中心的坐标
radius: 辐射半径
centerColor: 辐射中心的颜色
edgeColor: 辐射边缘的颜色
tileMode: 辐射范围之外的着色模式

1.1.2.3 SweepGradient 扫描渐变

val shader = SweepGradient(300f, 300f, Color.parseColor("#E91E63"),
Color.parseColor("#2196F3"))
paint.shader = shader
canvas.drawCircle(300f, 300f, 200f, paint)

构造方法:

SweepGradient(float cx, float cy, int color, int color)

参数:

cx, cy:扫描的中心
color0:扫描的起始颜色
color1:扫描的终止颜色

1.1.2.4 BitmapShader

用Bitmap来着色,也就是用Bitmap的像素来作为图形或文字的填充

// 加载原始的Bitmap
val originalBitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)

//图形的中心坐标和半径
val centerX = 200f
val centerY = 200f
val radius = 200f

// 计算缩放比例
val scale = Math.min(
radius * 2 / originalBitmap.width.toFloat()
radius * 2 / originalBitm.height.toFloat()
)

//创建缩放矩阵
val matrix = Matrix()
martix.postScale(scale, scale)

//缩放 Bitmap
val scaledBitmap = Bitmap.createBitmap(
originalBitmap,
0,
0,
originalBitmap.width,
originalBitmap.height,
true
)

val shader = BitmapShader(scaledBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
paint.shader = shader
canvas.drawCircle(centerX, centerY, radius, paint)

构造方法:

BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

参数:

bitmap: 用来作模板的Bitmap对象
tileX: 横向的TileMode
tileY:纵向的TileMOde

1.1.2.5 ComposeShader 混合着色器

所谓混合,就是把两个Shader一起使用

val originalBitmap1 = BitmapFactory.decodeResource(resource, R.drawable.batman)
val centerX = 200f
val centerY = 200f
val radius = 200f
val scale1 = Math.min(radius * 2 / originalBitmap1.width.toFloat(),
radius * 2 / originalBitmap1.height.toFloat())
val matrix1 = Matrix()
matrix1.postScale(scale1, scale1)
val scaledBitmap1 = Bitmap.createBitmap(
originalBitmap1,
0,
0,
originalBitmap1.width,
originalBitmap1.height,
matrix1,
true
)
val shader1 = BitmapShader(scaledBitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val originalBitmap2 = BitmapFactory.decodeResource(resource, R.drawable.batman_logo)

val scale2 = Math.min(radius * 2/ originalBitmap2.width, radius * 2/ originalBitmap2.height)
val matrix2 = Matrix()
matrix2.postScale(scale2, scale2)
val scaledBitmip2 = Bitmap.createBitmap(
originalBitmap2,
0,
0,
originalBitmap2.width
origibalBitmap2.height
matrix2,
true
)
val shader2 = BitmapShader(scaledBitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)

val shader = ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER)
paint.shader = shader
canvas.drawCircle(300f, 300f, 300f, paint)

构造方法:

ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)

参数:

shaderA, shaderB: 两个相继使用的Shader
mode: 两个Shader的叠加模式,即shaderA和shaderB应该怎么样共同绘制

PorterDuff.Mode是用来指定两个图像共同绘制时的颜色策略的。PoterDuff.Mode一共有17个,可以分为两类:

Alpha合成(Alpha Compositing)

混合(Blending)

1.2 setColorFilter(ColorFilter colorFilter)

ColorFilter 这个类,它的名字已经足够解释它的作用:为绘制设置颜色过滤。颜色过滤的意思,就是为绘制的内容设置一个统一的过滤策略,然后Canvas.drawXXX()方法会对每个像素都进行过滤后再绘制出来。

1.2.1 LightingColorFilter

这个LightingColorFilter是用来模拟简单的光照效果的

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

若是要使用LightingColorFilter并保持原样,则将mul设置为0xfffff, add设置为0x000000

R' = R * 0xff / 0xff + 0x0 = R // R' = R
G' = G * 0xff / 0xff + 0x0 = G // G' = G
B' = B * 0xff / 0xff + 0x0 = B // B' = B

基于这个基本,就可以修改一下做出其它的filter。比如,如果你想去掉原像素中的红色,可以把它的mul改为0xffff,那么它的计算过程就是:

R' = R * 0x0 / 0xff + 0x0 = 0 // 红色被移除
G' = G * 0xff / 0xff + 0x0 = G
B' = B * 0xff / 0xff + 0x0 = B

具体效果是这样的:

val lightingColorFilter = LightingColorFilter(0x00ffffff, 0x000000)
paint.colorFilter = lightingColorFilter

1.2.2 PorterDuffColorFilter

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

1.2.3 ColorMatrixColorFilter

ColorMatrixColorFilter使用一个ColorMatrix对颜色进行处理。ColorMatrix这个类,内部是一个4*5的矩阵:

[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]

通过计算,ColorMatiex可以把想要绘制的像素进行转换。对于颜色[R,G,B,A],转换算法是这样的:

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有一些自带的方法可以做简单的转换,例如可以使用setSaturaion(float sat)来设置饱和度

val bitmap = BitmapFactory.decodeResource(resources, R.drawale.batman)
val colorMatrix = ColorMatrix()
colorMatrix.setSaturation(0f)
val colorFilter = ColorMatrixColorFilter(colorMatrix)
paint.colorFilter = colorFilter
canvas.drawBitmap(bitmap, 0f, 0f, paint)

1.3 setXfermode(Xfermode xfermode)

Xfermode指的是你要绘制的内容和Canvas的目标位置的内容应该怎样结合计算出最终的颜色。但通俗地说,其实就是要以你绘制的内容作为源图像,以View中已有的内容作为目标图像,选取一个Poteruff.Mode作为绘制颜色处理的方案。

val xfermode = PoterDuffXfermode(PorterDuff.Mode.DST_IN)
canvas.drawBitmap(rectBitmap, 0f, 0f, paint) // 画方
paint.xfermode = xfermode // 设置Xfermode
canvas.drawBitmap(circleBitmap, 0f, 0f, paint) // 画圆
paint.xfermode = null // 用完及时清除Xfermode

又是PorterDuff.Mode。PorterDuff.Mode在Paint一共有三处API,它们的工作原理都一样,只是用途不同:

  • ComposeShader:混合两个Shader
  • PorterDuffColorFilter:增加一个单色的ColorFilter
  • Xfermode:设置绘制内容和View中已有内容的混合计算方式

注意事项

Xfermode的使用很简单,不过有两点需要注意:

1、使用离屏缓冲(Off-screen Buffer)

实质上,上面这段例子代码,如果直接执行的话是不会绘制出图中效果的

为什么:

照逻辑我们会认为,在第二步画圆的时候,跟它共同计算的是第一步绘制的方形。但实际上,却是整个 View的显示区域都在画圆的时候参与计算,并且 View自身的底色并不是默认的透明色,而且是遵循一种迷之逻辑,导致不仅绘制的是整个圆的范围,而且在范围之外都变成了黑色。

通过使用离屏缓冲,把要绘制的内容单独绘制在缓冲层, Xfermode的使用就不会出现奇怪的结果了。使用离屏缓冲有两种方式:

Canvas.saveLayer()

saveLayer()可以做短时的离屏缓冲。使用方法很简单,在绘制代码的前后各加一行代码,在绘制之前保存,绘制之后恢复:

val saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG)
val xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
val bitmap = BitmapFactory.decodeResource(resource, R.drawable.batman)
canvas.drawBitmap(bitmap, 0f, 0f, paint)
paint.xfermode = xfermode
val bitmap2 = BitmapFactroy.decodeResource(resource, R.drawable.batman_logo)
canvas.drawBitmap(bitmap2, 0f, 0f, paint)
paint.xfermode = null
canvas.resotreToCount(saved)

View.setLayerType()

View.setLayerType()是直接把整个 View都绘制在离屏缓冲中。 setLayerType(LAYER_TYPE_HARDWARE)是使用 GPU 来缓冲, setLayerType(LAYER_TYPE_SOFTWARE)是直接直接用一个Bitmap来缓冲。

2、控制好透明区域

使用 Xfermode 来绘制的内容,除了注意使用离屏缓冲,还应该注意控制它的透明区域不要太小,要让它足够覆盖到要和它结合绘制的内容,否则得到的结果很可能不是你想要的。

好,到此为止,前面讲的就是Paint的第一类 API——关于颜色的三层设置:直接设置颜色的 API 用来给图形和文字设置颜色; setColorFilter()用来基于颜色进行过滤处理;setXfermode()用来处理源图像和 View已有内容的关系。

效果

2.1 setAntiAlias (boolean aa) 设置抗锯齿

抗锯齿默认是关闭的,如果需要抗锯齿,需要显式地打开。

paint.isAntiAlias = true

另外,除了setAntiAlias(aa)方法,打开抗锯齿还有一个更方便的方式:构造方法。创建 Paint对象的时候,构造方法的参数里加一个

ANTI_ALIAS_FLAG的flag,就可以在初始化的时候开启抗锯齿

val paint = Paint(Paint.ANTI_ALIAS_FLAG)

2.2 setStyle (Paint.Sytle style)

setStyle(style)用来设置图形是线条风格还是填充风格的(也可以二者并用):

paint.style = Paint.Style.FILL // FILL 模式,填充
canvas.drawCircle(300f, 300f, 200f, paint)
paint.style = Paint.Style.STROKE //STROKE 模式,画线
canvas.drawCircle(300f, 300f, 200f, paint)
paint.style = Paint.Style.FILL_AND_STROKE // FILL_AND_STROKE 模式,填充 + 画线
canvas.drawCircle(300f, 300f, 200f, paint)

FILL模式是默认模式,所以如果之前没有设置过其他的 Style,可以不用 setStyle(Paint.Style.FILL) 这句。

2.3 线条形状

设置线条形状一共有4个方法:setStrokeWidth(float width),setStrokeCap(Paint.Cap cap),setStrokeJoin(Paint.Join),setStrokeMiter(float miter)

2.3.1 线条形状

设置线条宽度。单位为像素,默认值是 0。

paint.style = Paint.Style.STROKE
paint.strokeWidth = 1f
canvas.drawCircle(150f, 125f, 100f, paint)
paint.strokeWidth = 5f
canvas.drawCircle(400f, 125f, 100f, paint)
paint.strokeWidth = 40f
canvas.drawCircle(650f, 125f, 100f, paint)

线条宽度 0 和 1 的区别

默认情况下,线条的宽度为0,但这个时候它依然能够画出线,线条的宽度为1像素。那么它和线条宽度为1有什么区别呢?

可以为Canvas设置Matrix来实现几何变换,2像素的线条在Canvas放大两倍后会被以4像素绘制,而当线条宽度被设置为0是,它的宽度就被固定为1像素,就算Canvas通过几何变换被放大,它依然会被以1像素宽度来绘制。

2.3.2 setStrokeCap(Paint.Cap cap)

设置线头的形状。线头形状有三种:BUTT平头、ROUND圆头、SQUARE方头。默认为BUTT。

paint.strokeCap = Paint.Cap.BUTT

2.3.3 setStrokeJoin(Paint.Join join)

设置拐角的形状。有三个值可以选择:MITER尖角、BEVEL平角和ROUND圆角。默认为MITER

2.3.4 setStrokeMiter(float miter)

这个方法是对于 setStrokeJoin()的一个补充,它用于设置MITER型拐角的延长线的最大值。当延长线过长时,就会被转为BEVEL型。

色彩优化

Paint的色彩优化有两个昂发:setDither(boolean dither) 和 setFilterBitmap(boolean filter)

2.4.1 setDither(boolean dither)

paint.isDither = true

2.4.2 setFilterBitmap(boolean filter)

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

paint.isFilterBitmap = true

setPathEffect(PathEffect effect)

使用PathEffect来给图形的轮廓设置效果。对Canvas所有的图形绘制有效,也就是drawLine(),drawCircle(),drawPath()这些方法。

Android 中的 6 种 PathEffectPathEffect 分为两类,单一效果的 CornerPathEffect DiscretePathEffect DashPathEffect PathDashPathEffect ,和组合效果的 SumPathEffect ComposePathEffect

2.5.1 CornerPathEffect

把所有拐角变成圆角

val pathEffect = CornerPathEffect(20f)
paint.pathEffect = pathEffect

它的构造方法 CornerPathEffect(float radius) 的参数 radius 是圆角的半径。

2.5.2 DiscretePathEffect

val pathEffect = DiscretePathEffect(20f, 5f)
paint.pathEffect = pathEffect

DiscretePathEffect 具体的做法是,把绘制改为使用定长的线段来拼接,并且在拼接的时候对路径进行随机偏离。它的构造方法 DiscretePathEffect(float segmentLength, float deviation) 的两个参数中, segmentLength 是用来拼接的每个线段的长度, deviation 是偏离量。这两个值设置得不一样,显示效果也会不一样。

2.5.3 DashPathEffect

使用虚线来绘制线条。

val pathEffect: PathEffect = DashPathEffect(floatArrayOf(20f, 10f, 5f, 10f), 0f)
paint.pathEffect = pathEffect

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

2.5.4 PathDashPathEffect

这个方法比 DashPathEffect 多一个前缀 Path ,所以顾名思义,它是使用一个 Path 来绘制「虚线」。具体看图吧:

val pathEffect: PathEffect = PathDashPathEffect(dashPath, 40f, 0f, PathDashPathEffect.Style.TRANSLATE)
paint.pathEffect = pathEffect

它的构造方法 PathDashPathEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style) 中, shape 参数是用来绘制的 Pathadvance 是两个相邻的 shape 段之间的间隔,不过注意,这个间隔是两个 shape 段的起点的间隔,而不是前一个的终点和后一个的起点的距离; phaseDashPathEffect 中一样,是虚线的偏移;最后一个参数 style,是用来指定拐弯改变的时候 shape 的转换方式。style 的类型为 PathDashPathEffect.Style ,是一个 enum ,具体有三个值:

  • TRANSLATE:位移
  • ROTATE:旋转
  • MORPH:变体

2.5.5 SumPathEffect

这是一个组合效果类的 PathEffect 。它的行为特别简单,就是分别按照两种 PathEffect 分别对目标进行绘制。

val dashEffect = DashPathEffect(floatArrayOf(20f, 10f), 0f)
val discreteEffect = DiscreatePathEffect(20f, 5f)
pathEffect = SumPathEffect(dashEffect, discreteEffect)

2.5.6 ComposePathEffect

val dashEffect = DashPathEffect(floatArrayOf(20f, 10f), 0f)
val discreateEffect = DiscretePathEffect(20f, 5f)
val pathEffect = ComposePathEffect(dashEffect, discreteEffect)

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

在之后绘制的内容下面加一层阴影

val text = "hyq"
paint.setShadowLayer(10f, 0f, 0f, Color.RED)
canvas.drawText(text, 20f, 300f, paint)

radius 是阴影的模糊范围; dx dy 是阴影的偏移量; shadowColor是阴影的颜色。

如果要清除阴影层,使用 clearShadowLayer()

注意:

  • 在硬件加速开启的情况下, setShadowLayer() 只支持文字的绘制,文字之外的绘制必须关闭硬件加速才能正常绘制阴影。
  • 如果 shadowColor是半透明的,阴影的透明度就使用 shadowColor自己的透明度;而如果 shadowColor是不透明的,阴影的透明度就使用 paint的透明度。

2.7 setMaskFilter(MaskFilter maskfilter)

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

到现在已经有两个 setXxxFilter(filter)了。前面有一个setColorFilter(filter),是对每个像素的颜色进行过滤;而这里的setMaskFilter(filter) 则是基于整个画面来进行过滤

MaskFilter有两种BlurMaskFilter和 EmbossMaskFilter。

2.7.1 BlurMaskFilter

模糊效果的 MaskFilter

val maskFilter = BlurMaskFilter(50f, BlurMaskFilter.Blur.NORMAL)
paint.maskFilter = maskFilter
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)
canvas.drawBitmap(bitmap, 100f, 100f, paint)

它的构造方法 BlurMaskFilter(float radius, BlurMaskFilter.Blur style) 中, radius 参数是模糊的范围, style 是模糊的类型。一共有四种:

  • NORMAL: 内外都模糊绘制
  • SOLID: 内部正常绘制,外部模糊
  • INNER: 内部模糊,外部不绘制
  • OUTER: 内部不绘制,外部模糊(什么鬼?)

2.7.2 EmbossMaskFilter

浮雕效果的 MaskFilter

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)
canvas.drawBitmap(bitmap, 100f, 100f, paint)
val maskFilter = EmbossMaskFilter(floatArrayOf(0f, 1f, 1f), 0.2f, 8f, 10f)
paint.maskFilter = maskFilter
canvas.drawBitmap(bitmap, 100f, 100f, paint)

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

2.8 获取绘制的 Path

这是效果类的最后一组方法,也是效果类唯一的一组 get 方法。

这组方法做的事是,根据 paint 的设置,计算出绘制 Path 或文字时的实际 Path

2.8.1 getFillPath(Path src, Path dst)

「实际 Path」。所谓实际 Path ,指的就是 drawPath() 的绘制内容的轮廓,要算上线条宽度和设置的 PathEffect

默认情况下(线条宽度为 0、没有 PathEffect),原 Path 和实际 Path 是一样的;而在线条宽度不为 0 (并且模式为 STROKE 模式或 FLL_AND_STROKE ),或者设置了 PathEffect 的时候,实际 Path 就和原 Path 不一样了:

通过 getFillPath(src, dst) 方法就能获取这个实际 Path。方法的参数里,src 是原 Path ,而 dst 就是实际 Path 的保存位置。 getFillPath(src, dst) 会计算出实际 Path,然后把结果保存在 dst 里。

2.8.2 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」。文字的绘制,虽然是使用 Canvas.drawText() 方法,但其实在下层,文字信息全是被转化成图形,对图形进行绘制的。 getTextPath() 方法,获取的就是目标文字所对应的 Path 。这个就是所谓「文字的 Path

3 drawText() 相关

Paint 有些设置是文字绘制相关的,即和 drawText() 相关的。

4 初始化类

这一类方法很简单,它们是用来初始化 Paint 对象,或者是批量设置 Paint 的多个属性的方法。

4.1 reset()

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

4.2 set(Paint src)

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

4.3 setFlags(int flags)

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

paint.flags = Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG

这行代码,和下面这两行是等价的:

paint.setAntiAlias(true);
paint.setDither(true);