一、Paint介绍
Paint画笔,常与Canvas、Bitmap、Path等一起使用,用于绘制自定义View。Paint,保存了绘制几何图形、文本和位图的样式和颜色信息。常用的API也与颜色、效果(滤镜、颜色混合)、文本相关。
二、Paint API
源码中,Paint的方法内部都是调用的 native 方法。
-
构造方法。Paint有三个构造方法,一个无参构造方法 Paint(),两个有参构造方法Paint(int flags)、Paint(Paint paint)。**Paint()**调用的是 flag为0的 Paint(int flags)方法;Paint(Paint paint) 方法传入一个Paint对象,将传入的Paint对象的参数赋予新的Paint对象; Paint(int flags) 参数有:
1.1 ANTI_ALIAS_FLAG 抗锯齿。
1.2 FILTER_BITMAP_FLAG 在缩放的位图上启用双线性采样。
1.3 DITHER_FLAG 在绘制时启用抖动。
1.4 UNDERLINE_TEXT_FLAG 文本加下划线。
1.5 STRIKE_THRU_TEXT_FLAG 文本上加横线。
1.6 FAKE_BOLD_TEXT_FLAG 文本粗体。
1.7 LINEAR_TEXT_FLAG 文本的平滑线性缩放。启用此标志实际上不会缩放文本,而是调整文本绘制操作以优雅地处理缩放比例。启用此标志时,将禁用字体提示以防止缩放因子之间的形状变形,并且由于将生成大量字形图像而禁用字形缓存。应该与 SUBPIXEL_TEXT_FLAG标志一起使用,以防止字形位置在调整比例因子时捕捉到整个像素值。
1.8 SUBPIXEL_TEXT_FLAG 用于启用子像素定位文本。
1.9 EMBEDDED_BITMAP_TEXT_FLAG 在绘制文本时使用位图字体。
1.10 HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG。HIDDEN_DEFAULT_PAINT_FLAGS 是所有Paint都创建的时候一定会默认设置的flag,其中DEV_KERN_TEXT_FLAG是标注不在使用的flag,不管他,EMBEDDED_BITMAP_TEXT_FLAG 是在绘制文本时使用位图字体的设置,表示所有的paint对象都默认有这个设置。
-
颜色相关:
2.1 setColor(Color.RED) 设置颜色
2.2 setARGB(255, 255, 255, 0) 设置 Paint对象颜色,范围为0~255
2.3 setAlpha(200) 设置alpha不透明度,范围为0~255
2.4 setColorFilter(colorFilter) 设置颜色过滤
-
样式相关:
3.1 **setAntiAlias(true)**抗锯齿
3.2 setStyle(Paint.Style.FILL) 描边效果 有三种参数:FILL(填充,默认效果)、STROKE(描边)、FILL_AND_STROKE(填充加描边)
3.3 setStrokeWidth(4) 描边宽度
3.4 setStrokeCap(Paint.Cap.ROUND) 圆角效果 有三种参数:BUTT(默认效果)、ROUND(圆形)、SQUARE(方形)
3.5 setStrokeJoin(Paint.Join.MITER) 拐角风格 MITER(斜切,默认),ROUND(圆角)、BEVEL(斜角) -
滤镜
4.1 setShader(new SweepGradient(200, 200, Color.BLUE, Color.RED)) 设置渲染器 此方法可设置多种渲染器,这里是环形渲染器,渲染器相关在后文会详细描述。
4.2 setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)) 设置图层混合模式 后文详述。
4.3 setColorFilter(new LightingColorFilter(0x00ffff, 0x000000)) 设置颜色过滤器 后文详述。
4.4 setFilterBitmap(true) 设置双线性过滤 使图片效果更加平滑。效果如下图
4.5 setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL)) 设置画笔遮罩滤镜,传入半径和样式,可设置文字和图片的遮罩,样式种类:NORMAL、SOLID、OUTER、INNER -
字体
5.1 setTextScaleX(2) 设置文本缩放倍数
5.2 setTextSize(38) 设置字体大小
5.3 setTextAlign(Paint.Align.LEFT) 设置对齐方式
5.4 setUnderlineText(true) 设置下划线
5.5 getTextBounds(str, 0, str.length(), rect) 测量文本大小,将文本大小信息存放在rect中
5.6 measureText(str) 获取文本的宽
5.7 getFontMetrics() 获取字体度量对象
三、各种滤镜(Paint颜色处理)
- 前两种方式比较简单就不赘述了。
-
第三种设置着色器。Shader有5个子类:
2.1 LinearGradient(线性渐变器)。构造方法:LinearGradient(float x0, float y0, float x1, float y1, int colors[],float positions[], TileMode tile)------x0,y0渐变开始点坐标,x1,y1渐变结束点坐标,colors颜色数组和后面的positions数组对应,positions数组数值都在0-1之间,表示前面的颜色数组开始渐变的位置,可以传null,tile用于指定控件区域大于渐变区域时,空白区域的填充方式。
2.2 RadialGradient(圆形渲染器)。构造方法:RadialGradient(float centerX, float centerY, float radius,int colors[], float stops[],TileMode tileMode)------centerX,centerY辐射中心的坐标,radius 辐射半径,centerColor辐射中心的颜色,edgeColor辐射边缘的颜色,tileMode辐射范围之外的着色规则。
2.3 SweepGradient(扫描渲染)。构造方法:SweepGradient(float cx, float cy, int color0, int color1)------cx,cy扫描的中心,color0扫描的起始颜色,color1扫描的终止颜色。
2.4 BitmapShader(位图渲染)。构造方法:BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY)------bitmap用来做模版的bitmap,tileX横向的着色规则,tileY纵向着色规则。
2.5 ComposeShader(组合渲染)。构造方法:ComposeShader( Shader shaderA, Shader shaderB, Xfermode mode);ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode);shaderA,shaderB:要混合的两种shader,Xfermode mode: 组合两种shader颜色的模式(Xfermode 中包含PorterDuff.Mode 的设置,即,最终还是PorterDuff.Mode 设置两个渲染器叠加模式),PorterDuff.Mode mode: 组合两种shader颜色的模式
-
TileMode
3.1 CLAMP 当canvas大于渲染器的位置时,按最后一个像素铺开未覆盖区域。
3.2 REPEAT 当canvas大于渲染器的位置时,重复处理。
3.3 MIRROR 当canvas大于渲染器的位置时,镜像处理。
-
Xfermode 图层混合
4.1 GitHub上有个Google的Api示例,GoogleApiDemo。上面在app/src/maim/java/com/example/android/apis/graphics/Xfermodes.java中有Xfermode相关的代码实现。这里取其中的模式种类代码和实现结果截图,来解释Xfermode各种模式的实现效果:
//效果作用于src源图像区域
private static final Xfermode[] sModes = {
//所绘制不会提交到画布上
new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
//显示上层绘制的图像
new PorterDuffXfermode(PorterDuff.Mode.SRC),
//显示下层绘制图像
new PorterDuffXfermode(PorterDuff.Mode.DST),
//正常绘制显示,上下层绘制叠盖
new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
//上下层都显示,下层居上显示
new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
//取两层绘制交集,显示上层
new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
//取两层绘制交集,显示下层
new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
//取上层绘制非交集部分,交集部分变成透明
new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
//取下层绘制非交集部分,交集部分变成透明
new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
//取上层交集部分与下层非交集部分
new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
//取下层交集部分与上层非交集部分
new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
//去除两图层交集部分
new PorterDuffXfermode(PorterDuff.Mode.XOR),
//取两图层全部区域,交集部分颜色加深
new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
//取两图层全部区域,交集部分颜色点亮
new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
//取两图层交集部分,颜色叠加
new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
//取两图层全部区域,交集部分滤色
new PorterDuffXfermode(PorterDuff.Mode.SCREEN),
//取两图层全部区域,交集部分饱和度相加
new PorterDuffXfermode(PorterDuff.Mode.ADD),
//取两图层全部区域,交集部分叠加
new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)
};
图层混合时需调用禁止硬件加速方法,图层混合有些api不支持硬件加速
禁止硬件加速方法(使用一个bitmap进行缓冲):setLayerType(LAYER_TYPE_SOFTWARE, mPaint);
三处使用图层混合的地方:ComposeShader(Paint的组合渲染)、paint.xfermode(Paint的图层混合设置)、 PorterDuffColorFilter(颜色过滤器,一种滤色镜,可用于使用单一颜色和特定颜色对源像素进行着色)
注意:禁止硬件加速和设置背景色不能放在onDraw方法里,会导致onDraw方法多次调用,禁止硬件加速–>onDraw不停调用(log刷屏),设置背景颜色–>onDraw两次调用
-
LightingColorFilter 设置颜色滤镜,可以调整图片的色调。
构造方法:LightingColorFilter( int mul, int add),两个参数与颜色的计算方法:R*mul + R +add = R;RGB三个值都这样计算,mul和add值样例:0x00ffff,十六进制,当mul的高两位是00时,表示红色被过滤了,中间两位为00,绿色被过滤,低两位表示蓝色被过滤,mul和add混合着可以调节图片色调
-
PorterDuffColorFilter 设置颜色和图片混合,设置混合模式。
构造方法:PorterDuffColorFilter(int color, PorterDuff.Mode mode) color表示设置颜色滤镜,mode是Xfermode混合模式,参数见上文的Xfermode[]。
- ColorMatrixColorFilter 使用颜色矩阵修改图片颜色,
p图软件的各种滤镜效果都可以用这种矩阵实现,例如胶片、电影等滤镜效果。
有个ColorMatrix的类,定义了各种方法操作矩阵:
7.1 colorMatrix.setScale(1,1,1,1); 亮度调节。参数传入1表示原图,四个参数分别表示RGBA的值。
7.2 colorMatrix.setSaturation(1); 饱和度调节 0-无色彩,1-默认,>1饱和度加强
7.3 colorMatrix.setRotate(int axis, float degrees); axis颜色通道 0-R,1-G,2-B,degrees颜色在三角坐标旋转的角度,这里就不详述了,具体的可以百度一下这一块详解的文章
四、离屏绘制
//离屏绘制
int layerId = canvas.saveLayer(0,0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
//todo 进行绘制
canvas.restoreToCount(layerId);
离屏绘制时,对canvas进行的操作都不会影响到当前的canvas上。
离屏缓冲,也通俗地称之为层,这个概念很简单,我们在绘图的时候新建一个“层”,所有的绘制操作都在该层上而不影响该层以外的图像,比如代码中我们在绘制了画布颜色和左右上方两个方形后就新建了一个图层来绘制中间的大正方形,这个方形和左右上方的方形是在两个不同的层上的。很类似PS中的层。详解Paint的setXfermode(Xfermode xfermode)
图层混合要配合离屏缓冲一起使用,避免图层混合出现混乱。在离屏缓冲绘制完成时要用mPaint.setXfermode(null);方法清除混合模式。
View.setLayerType()将整个View设置离屏缓冲。