先熟悉paint的属性:
setARGB(255,255,255,0) 通过ARGB设置颜色
alpha = 200//设置不透明度,范围0-255
isAntiAlias=true//抗锯齿
style=Paint.Style.FILL//描边效果
strokeWidth=4f//描边宽度
strokeCap= Paint.Cap.ROUND//画笔结尾的时候形状这里设置圆形
strokeJoin= Paint.Join.MITER//拐角风格 //miter是锐角相交 还有圆角相交,直线相交
shader = SweepGradient(200f,200f,Color.BLUE,Color.RED)//设置环形渲染器
xfermode = PorterDuffXfermode(PorterDuff.Mode.DARKEN)//设置图层混合模式
colorFilter = LightingColorFilter(0x00ffff,0x000000)//设置颜色过滤器
isFilterBitmap=true//设置双线性过滤
maskFilter = BlurMaskFilter(10f,BlurMaskFilter.Blur.NORMAL)//设置画笔这招滤镜,传入度数和样式
textScaleX= 2f//设置文本缩放倍数
textSize=38f
textAlign= Paint.Align.LEFT//对其方式
isUnderlineText= true//设置下划线
val temp= "我在学习安卓进阶技术"
val rect = Rect()
getTextBounds(temp,0,temp.length,rect)//测量文本大小,将文本大小信息存放在rect中
val textWidth = measureText(temp)
val textMetrics = fontMetrics
接下来是重点研究渲染器
渲染器分为:
1.线性渲染,LinearGradient
2.环形渲染 RadialGradient
3.扫描渲染 RadialGradient
4.位图渲染 BitmapShader
5.组合渲染 ComposeShader
分别看下参数 和 效果
线性渲染:
LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[],
@Nullable float positions[], @NonNull TileMode tile)
(x0,y0) 渐变起始坐标
(x1,y1)渐变结束坐标
color0 渐变开始点颜色,16进制的颜色表示,必须带有透明度
color1,渐变结束颜色
colors渐变数组
positions 位置数组,position的取值范围[0,1],作用是置顶某个位置的颜色值,如果null,渐变就是线性变化
title:用于指定控件区域大于指定的渐变区域是,空白区域的颜色填充方式
shader= LinearGradient(0f,0f,500f,500f ,
intArrayOf(Color.RED,Color.BLUE,Color.GREEN), floatArrayOf(0f,0.7f,1f),Shader.TileMode.REPEAT)
paint.shader = shader
// canvas?.drawCircle(250f,250f,250f,paint)
canvas?.drawRect(0f,0f,1000f,1000f,paint)
效果: 因为 这个画笔设置了3个颜色.红,蓝,绿 .分别在 0, 0.7 , 1 这3个位置坐渐变, 由于起始点是0,0 也就是屏幕左上角,结束点时是 500,500, 那么 而矩形的宽高是1000*1000 所以 画笔是花不完这么大的区域 用到tileMode 这个属性,设置Shader.TileMode.REPEAT
表示如果填充不完,就重复填充也就是以500,500,为起点 结束点 是(500+500,500+500)正好1000,1000 看到效果是画笔的2次重复绘制
环形渲染
RadialGradient(float centerX, float centerY, float radius,@NonNull @ColorInt int colors[], @Nullable floatstops[],@NonNull TileMode tileMode)
centerX centerY 辐射中心的坐标
radius 辐射半径
centerColor 辐射中心的颜色
edgeColor 辐射边缘的颜色
colors 渐变颜色数组
stoops 渐变位置数组,类似扫描的positions数组 取[0,1],中心为0,半径到达位置为1.0f
titleMode 未覆盖意外的填充颜色模式
shader= RadialGradient(250f,250f,250f,
intArrayOf(Color.GREEN,Color.YELLOW,Color.RED),null,Shader.TileMode.CLAMP)
paint. shader = shader
canvas?.drawCircle(250f,250f,250f,paint)
扫描渲染
SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1)
* @param cx 渐变中心的坐标
* @param cy 渐变中心的坐标
* @param color0 渐变开始结束颜色
* @param color1 The color to use at the end of the sweep
shader= SweepGradient(250f,250f,Color.RED,Color.GREEN)
paint.shader=shader
canvas?.drawCircle(250f,250f,250f,paint)
圆心250,250 半径250 以红色开始 绿色结束扫描一周渐变
位图渲染
BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
* @param bitmap 构造BitmapShader使用的bitmap
* @param tileX 水平方向的TileMode
* @param tileY 垂直方向的TileMode
* REPEAT 绘制区域超过渲染区域的部分,重复排版
* CLAMP 绘制区域超过渲染区域的部分,重复最后一个像素拉伸排版
* MIRROR 绘制区域超过渲染区域的部分 镜像翻转排版
private val mBitmap :Bitmap by lazy{
BitmapFactory.decodeResource(resources, R.mipmap.test)
}
shader= BitmapShader(mBitmap,Shader.TileMode.MIRROR,Shader.TileMode.MIRROR)
paint.shader=shader
canvas?.drawCircle(250f,250f,250f,paint)
// canvas?.drawRect(0f,0f,mBitmap.width.toFloat(),mBitmap.height.toFloat(),paint)
// canvas?.drawRect(0f,0f,500f,500f,paint)
可以看出来 图片如果水平宽度不够了, 他会水平镜像复制平铺,如果垂直方向 高度不够,会镜像赋值图片,这就是mirror属性
组合渲染
BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
* @param shaderA 要混合的2种shader
* @param shaderB 要混合的2种shader
* @param PorterDuff.Mode mode 组合2中shader颜色的模式
* @param Xfermode mode 组合2中shader颜色的模式
val bitmapShader = BitmapShader(mBitmap,Shader.TileMode.REPEAT,Shader.TileMode.REPEAT)
val linearGradient = LinearGradient(0f,0f,500f,500f , intArrayOf(Color.RED,Color.GREEN,Color.BLUE),null,Shader.TileMode.MIRROR )
shader= ComposeShader(bitmapShader,linearGradient,PorterDuff.Mode.MULTIPLY)
paint.shader=shader
canvas?.drawCircle(250f,250f,250f,paint)
第一个是位图渲染, 用的镜像平铺,第二个是线性渲染,红绿蓝渐变.用的也是镜像,这2个渲染器组合一下,效果很帅
逐个研究18种图层混合模式
//所绘制不会提交到画布上
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)
离屏绘制
通过使用离屏缓冲吧要绘制的内容单独绘制在缓冲层,保证Xfermode的使用不会出现错误的结果.
Canvas.saveLayer()可以做短时的离屏缓冲,再绘制之前保存,绘制之后恢复
int saveId=canvs.saveLayer(0,0,width,height,Canvas.All_SAVE_FLAG);
Canvas.drawBitmap(rectBitmap,0,0,paint);//画方
Paint.setXfermode(xfermode);//设置Xfermode
Canvas.drawBitmap(circleBitmap,0,0,paint);//画圆
Paint.setXfermode(null);用完及时清除Xfermode
canvas.restoreToCount(saveId)
View.setLayerType()直接把整个View都绘制在离屏绘制缓冲中
setLayerType(LAYER_TYPE_HARDWARE)使用GPU来缓冲
setLayerType(LAYER_TYPE_SOFTWARE)使用一个bitmap来缓冲
LightingColorFilter滤镜
构造方法 (作用 :改变 图片RGBA的值 从而改变图片颜色)
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
其实就是mul一般是2个16进制 范围00 ~ff 然后除以 0xff 就相当于 一个百分比 再乘上目标颜色的 值
而add就是直接加一个颜色值
用法:
class MyLightingColorFilter : View {
private var mPaint: Paint? = null
private var mBitmap: Bitmap? = null
constructor(context: Context) : super(context) {
mPaint = Paint()
mBitmap = BitmapFactory.decodeResource(resources, R.mipmap.girl)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
/************************************************color filter用法**********/
//去掉红色
// val colorFilter = LightingColorFilter(0x00ffff, 0x000000)
//原色
// val colorFilter = LightingColorFilter(0xffffff, 0x000000)
//加亮绿色
// val colorFilter = LightingColorFilter(0xffffff, 0x005500)
// mPaint?.let {
// it.colorFilter=colorFilter
// canvas?.drawBitmap(mBitmap,0f,0f,it)
// }
/*******************************colorFilter用法 结束***************************/
/***********************PorterDuffColorFilter用法***********************/
/**
* 相当于一张纯色图片 和原图的叠加 再加上 PorterDuff.Mode 模式
* 可选模式有Darken 重叠后颜色加深
* LIGHTEN 重叠后颜色调浅等等 具体看 PorterDuff.Mode 源码
*
*/
// val porterDuffColorFilter = PorterDuffColorFilter(Color.RED, PorterDuff.Mode.LIGHTEN)
// mPaint?.let {
// it.colorFilter=porterDuffColorFilter
// canvas?.drawBitmap(mBitmap,100f,100f,it)
// }
/******************************PorterDuffColorFilter用法结束*********************************/
/*******************colorMatrixColorFilter 用法***************************************/
// val colorMatrix = floatArrayOf(
// 1f, 0f, 0f, 0f, 0f,//red
// 0f, 1f, 0f, 0f, 0f,//green
// 0f, 0f, 1f, 0f, 0f,//blue
// 0f, 0f, 0f, 1f, 0f//alpha
// )
// 每一行 前4个事 RGBA的系数值 最后一个是偏移量 常见的 滤镜效果可以参考ColorFilter类中的ColorMatrix,用ColorFilterActivity打开
// val mColorMatrixColorFilter= ColorMatrixColorFilter(colorMatrix)
// mPaint?.colorFilter =mColorMatrixColorFilter
// canvas?.drawBitmap(mBitmap,100f,0f,mPaint)
/*******************colorMatrixColorFilter 用法结束****************************/
/*******************ColorMatrix 用法***************************************/
val colorMatrix = ColorMatrix()
// 亮度调节
// colorMatrix.setScale(1f, 1f, 1f, 1f)
//饱和度调节 0 -无色彩 1 默认 >1 饱和度加强
colorMatrix.setSaturation(1.5f)
//色度调节 第一个表示颜色通道 0,1,2,3 分别表示 RGBA
//第二个参数表示要修改 的值 具体操作可以看 setRotate 的源码
colorMatrix.setRotate(0, 45f)
val colorMatrixColorFilter = ColorMatrixColorFilter(colorMatrix)
mPaint?.colorFilter = colorMatrixColorFilter
canvas?.drawBitmap(mBitmap, 100f, 0f, mPaint)
/*******************ColorMatrix 用法结束***************************************/
}
}