博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Paint的用法总结
阅读量:5875 次
发布时间:2019-06-19

本文共 7452 字,大约阅读时间需要 24 分钟。

Paint的用法总结

上一期在总结canvas的用法时候谈到绘制需要的四个组件:一个保存像素的Bitmap,一个主持绘画操作的Canvas(往Bitmap写东西),一个绘制的基本元素(例如Rect,Path,Text,Btimap),一支画笔(用来描述绘画的颜色与风格)。

在上一期文章里总结了canvas的一些用法,那么这次就来总结一下画笔Paint的一些用法。 还是一样的套路,先看看类描述:Paint是持有绘制几何图形、文字、位图等样式、颜色信息的类,那么总结下来可以大致描述,Paint是描述的绘制样式以及颜色信息的类。

Paint关于颜色信息的描述

canvas在绘制的时候颜色也不完全由paint决定,canvas在画颜色以及位图的时候,颜色画出来的跟paint的颜色不一致,因为canva在画颜色的时候,颜色信息是直接设置到参数里的,这个颜色由参数的色值来决定;在画bitmap的时候,bitmap中有相关的颜色信息,绘制出来的颜色由bitmap的颜色信息来决定;其余的绘制颜色就由paint来决定。

Paint设置颜色

Paint设置颜色有两个方法,setcolor以及setARGB跟canvas的绘制颜色一样,比较简单,另外paint还有一个setAlpha方法,这个是只设置alpha信息的

Paint设置着色器

Paint除了直接设置颜色,还可以通过setShader方法设置着色器,其实用过ps的都知道,着色器其实就是一种颜色填充方式,单一的颜色,也可以看做是纯色的着色器,如果设置了着色器,那么颜色填充方式就以着色器的颜色信息为准。使用着色器并不能直接使用Shader类,应该使用其子类:

LinearGradient线性渐变

/**   *   * @param x0       渐变线开始点的x坐标   * @param y0       渐变线开始点的y坐标   * @param x1       渐变线结束点的x坐标   * @param y1       渐变线结束点的y坐标   * @param color0   渐变线的起始颜色   * @param color1   渐变线的结束颜色   * @param tile     平铺的模式(需要填充的面积大于渐变的区间时的平铺模式)*/    val linearGradient = LinearGradient(0f, 0f, 200f, 200f, Color.RED, Color.BLUE, Shader.TileMode.MIRROR)    mPaint.shader = linearGradient    canvas?.drawText("kevinxieyeah", 5f, 200f, mPaint)复制代码

还可以指定多个颜色的线性渐变

/** * * @param x0          渐变线开始点的x坐标 * @param y0          渐变线开始点的y坐标 * @param x1          渐变线结束点的x坐标 * @param y1          渐变线结束点的y坐标 * @param colors      颜色的int数组 * @param positions   位置的float数组 * @param tile        平铺的模式(需要填充的面积大于渐变的区间时的平铺模式)*/val linearGradient = LinearGradient(0f, 0f, 200f, 200f, intArrayOf(Color.RED, Color.BLUE, Color.GREEN), floatArrayOf(0f, 0.5f, 1f), Shader.TileMode.MIRROR)复制代码

还有一个tile模式,我们指定三个值 MIRROR

CLAMP
REPEAT

RadialGradient环形渐变

/** * * @param centerX     渐变的中心点x坐标 * @param centerY     渐变的中心点y坐标 * @param radius      渐变的半径 * @param centerColor 渐变的开始颜色 * @param edgeColor   渐变的结束颜色 * @param tileMode    填充模式 */val radialGradient = RadialGradient(300f, 300f, 500f, Color.RED, Color.GREEN, Shader.TileMode.CLAMP)mPaint.shader = radialGradientcanvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)复制代码

环形渐变也可以指定多个颜色值,跟线性渐变类似,填充模式跟线性渐变也类似

SweepGradient扫描渐变

/** * * @param cx       渐变的中心点x坐标 * @param cy       渐变的中心点y坐标 * @param color0   渐变的开始颜色 * @param color1   渐变的结束颜色 */val sweepGradient = SweepGradient(300f, 300f, Color.RED, Color.GREEN)mPaint.shader = sweepGradientcanvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)复制代码

扫描渐变也可以指定多个颜色值,跟线性渐变类似,但是没有填充模式

BitmapShader图片着色器

/** * @param bitmap 要填充的bitmap * @param tileX x方向的填充模式 * @param tileY y方向的填充模式 */val bitmapShader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)mPaint.shader = bitmapShadercanvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)复制代码

改变一下y方向的模式看看效果 REPEAT
MIRROR

ComposeShader组合着色器

val bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.a)val bitmapShader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.MIRROR)val radialGradient = RadialGradient(300f, 300f, 500f, Color.RED, Color.GREEN, Shader.TileMode.CLAMP)/** * @param shaderA  目标着色器 * @param shaderB  源着色器 * @param mode     混合模式*/val composeShader = ComposeShader(bitmapShader, radialGradient, PorterDuff.Mode.LIGHTEN)mPaint.shader = composeShadercanvas?.drawRect(Rect(0, 0, 1000, 1000), mPaint)复制代码

顾名思义,把着色器混合着用,后面可以传PorterDuff.Mode和XferMode,XferMode其实就是对PorterDuff.Mode的封装,所以还是需要了解每一种混合模式之间的区别。

PorterDuff.Mode

混合模式我们对照图来达到我们需要的效果就可以了

Paint设置ColorFilter

为绘制的内容提供颜色过滤,他有三个子类LightingColorFilter、PorterDuffColorFilter、ColorMatrixColorFilter,还是逐一使用看看效果先

LightingColorFilter

是不是有一种无法预测结果的感觉?其实颜色混合都有其对应的算法去处理颜色,网上看到扔物线大神这个对LightingColorFilter的解释,LightingColorFilter 的构造方法是 LightingColorFilter(int mul, int add) ,参数里的 mul 和 add 都是和颜色值格式相同的 int 值,其中 mul 用来和目标像素相乘,add 用来和目标像素相加

R' = R * mul.R / 0xff + add.RG' = G * mul.G / 0xff + add.GB' = B * mul.B / 0xff + add.B复制代码

PorterDuffColorFilter

val bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.a)mPaint.colorFilter = PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DARKEN)canvas?.drawBitmap(bitmap, 50f, 50f, mPaint)复制代码

PorterDuffColorFilter是使用一种特定的颜色对绘制的内容按照PorterDuff.Mode来进行处理

ColorMatrixColorFilter

还是借用扔物线大神的解释,ColorMatrixColorFilter 使用一个 ColorMatrix 来对颜色进行处理。 ColorMatrix 这个类,内部是一个 4x5 的矩阵

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

通过计算, ColorMatrix 可以把要绘制的像素进行转换。对于颜色 [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;复制代码

Paint设置XferMode

setXfermode其实就是将你绘制的内容作为源图像与canvas已经存在的内容目标图像按照设置的模式进行混合,其实默认的模式是SRC_OVER,也就是像我们常见的后画的内容覆盖先画的内容。

val xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)canvas?.drawRect(Rect(300, 300, 800, 800), mPaint)mPaint.xfermode = xfermodemPaint.color = Color.REDcanvas?.drawCircle(300f, 300f, 100f, mPaint)mPaint.xfermode = null复制代码

出现了奇怪的效果,绘制的圆变成了黑色,没有达到我们预期的裁剪效果,解决方法是将设置XferMode的绘制单独放在一个图层,通过saveLayer可以避免奇怪的效果

Paint关于样式的描述

Paint的flag配置

我们在创建paint的时候可以传递一个flag值,这些值对应的设置如下:

  • Paint.ANTI_ALIAS_FLAG :抗锯齿标志
  • Paint.FILTER_BITMAP_FLAG : 使位图过滤的位掩码标志
  • Paint.DITHER_FLAG : 使位图进行有利的抖动的位掩码标志
  • Paint.UNDERLINE_TEXT_FLAG : 下划线
  • Paint.STRIKE_THRU_TEXT_FLAG : 中划线
  • Paint.FAKE_BOLD_TEXT_FLAG : 加粗
  • Paint.LINEAR_TEXT_FLAG : 使文本平滑线性扩展的油漆标志
  • Paint.SUBPIXEL_TEXT_FLAG : 使文本的亚像素定位的绘图标志
  • Paint.EMBEDDED_BITMAP_TEXT_FLAG : 绘制文本时允许使用位图字体的绘图标志

我们可以通过设置flag来给paint设置这些配置,也可以用一些专门的帮助方法,比如:setAntiAlias、setDither、setLinearText、setSubpixelText、setUnderlineText、setStrikeThruText、setFakeBoldText、setFilterBitmap,这些方法都是对以上flag的帮助设置,用哪种方法都可以。

Paint的style

paint可以通过setStyle(Style style)方法来设置style,Style用三种模式,FILL(填充)、STROKE(描边)、FILL_AND_STROKE(填充以及描边)

val path = Path()path.lineTo(0f, 300f)path.lineTo(500f, 300f)path.lineTo(600f, 0f)canvas?.drawPath(path, mPaint)复制代码

从上面两张图对比就可以看出填充和描边的区别,但是记住填充并不是一定要闭合的区间,因为一旦paint的style是填充,那么他会默认将path按照闭合区间来填充

Paint的描边设置

我们可以通过setStrokeWidth来设置描边的宽度,用setStrokeCap来设置线条两头的形状

mPaint.strokeCap = Paint.Cap.BUTTcanvas?.drawLine(100f, 100f, 500f, 100f, mPaint)mPaint.strokeCap = Paint.Cap.ROUNDcanvas?.drawLine(100f, 200f, 500f, 200f, mPaint)mPaint.strokeCap = Paint.Cap.SQUAREcanvas?.drawLine(100f, 300f, 500f, 300f, mPaint)复制代码

还可以通过setStrokeJoin来设置线条相交处的处理

BEVEL

ROUND
MITER

setStrokeMiter是对于 setStrokeJoin() 的一个补充,它用于设置 MITER 型拐角的延长线的最大值,夹角太小时,就会造成尖角过长时,自动改用 BEVEL 的方式来渲染连接点

setPathEffect(PathEffect effect)是用来设置描边的效果,看一下有哪些子类

我们来分别设置看看效果

  • DashPathEffect(floatArrayOf(10f, 10f, 20f, 20f), 0f),第一个参数 intervals 是一个数组,它指定了虚线的格式:数组中元素必须为偶数(最少是 2 个),按照(画线长度、空白长度、画线长度、空白长度)的顺序排列,第二个参数 phase 是虚线的偏移量。

  • PathDashPathEffect(path, 10f, 0f, PathDashPathEffect.Style.ROTATE)是使用指定的Path来绘制描边。

  • CornerPathEffect(30f)就是对路径进行圆角

  • DiscretePathEffect(5f, 5f)是把绘制改为使用定长的线段来拼接,并且在拼接的时候对路径进行随机偏离。segmentLength 是用来拼接的每个线段的长度, deviation 是偏离量。

  • SumPathEffect(dashPathEffect, cornerPathEffect)把两个效果直接叠加在一起

  • ComposePathEffect(dashPathEffect, cornerPathEffect)把两个效果直进行组合成一个新的效果

Paint的色彩优化

Paint 的色彩优化有两个方法: setDither(boolean dither) 和 setFilterBitmap(boolean filter) 。它们的作用都是让画面颜色变得更加自然。

setDither设置抖动,在图像降低色彩深度绘制时,避免出现大片的色带与色块

setFilterBitmap设置双线性过滤,图像在放大绘制的时候,默认使用的是最近邻插值过滤,这种算法简单,但会出现马赛克现象;而如果开启了双线性过滤,就可以让结果图像显得更加平滑。

Paint的设置阴影

mPaint.setShadowLayer(30f, 0f, 0f, Color.RED)canvas?.drawText("kevinxie", 50f, 300f, mPaint)复制代码

Paint的设置遮罩过滤

遮罩其实就是在图像上面附加一层遮盖物,可以使用setMaskFilter(MaskFilter maskfilter)来进行设置,MaskFilter有EmbossMaskFilter、BlurMaskFilter两个子类,我们来使用一下看看效果

  • BlurMaskFilter模糊效果

    四种模糊的style

  • EmbossMaskFilter浮雕效果,相对于之前的BlurMaskFilter来说,EmbossMaskFilter的可用性比较低,因为它实现的效果不是很霸气。正如其名,他可以实现一种类似浮雕的效果,说白了就是让你绘制的图像感觉像是从屏幕中“凸”起来更有立体感一样。

上述两种效果已经过时,在4.0以上要看到效果需要关闭硬件加速

恩,差不多,就到这里了!!!

转载地址:http://ockix.baihongyu.com/

你可能感兴趣的文章
python模块-part2
查看>>
Nginx 安装配置 禁止使用IP访问 rewrite重写 别名设置 日志轮询
查看>>
PowerShell天天学——01
查看>>
Linux下DNS实战篇之主从同步
查看>>
centos7 安装之后 TAB无法自动补全 !?
查看>>
MFC标签页--对话框
查看>>
我的友情链接
查看>>
mysql主从+keepalived高可用
查看>>
11g rac ORA-01157问题处理
查看>>
国内code平台托管开源站点
查看>>
U盘的常见物理故障类型和故障表现汇总
查看>>
生产线上的nginx如何添加未编译安装模块
查看>>
面向过程与函数式编程区别的浅显理解
查看>>
你人生中的那口井挖了没有?
查看>>
“节”后余生蛇年的加班开始了
查看>>
web 客户端 移动设备 各种调试工具
查看>>
我的友情链接
查看>>
ubuntu修改IP地址和网关的方法
查看>>
mian(int argc,char *argv[])及getopt()函数
查看>>
CDN是什么作用在哪里?
查看>>