Android- 高级 -UI- 进阶之路 -(五)- 看完该篇文章 -Canvas- 你应该会了
override fun draw(canvas: Canvas) {super.draw(canvas)mPaint.strokeWidth = 10fmPaint.setColor(Color.RED)//1.canvas.drawLine(100f,100f,600f,600f,mPaint)//2.canvas.drawLines
(floatArrayOf(100f,100f,600f,600f),mPaint)//3. //第一个参数是一个坐标点组//第二个参数从哪个坐标点开始//第三个参数坐标点是取出 4 个数据 canvas.drawLines(floatArrayOf(100f,100f,600f,600f),0,4,mPaint)}
效果都一样
绘制点
//x,y 点坐标 void drawPoint(float x, float y, @NonNull Paint paint)//pts 坐标组,offset 从哪个点开始,count:取多少个点 void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,@NonNull Paint paint)//pts 坐标组 void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint)
//1canvas.drawPoint(100f, 100f, mPaint)
//2.var offset = 0var pts = floatArrayOf(500f + offset, 100f, 500f + offset, 200f,500f + offset, 300f, 500f + offset, 600f,500f + offset, 700f, 500f + offset, 800f,500f + offset, 900f, 500f + offset, 1000f)mPaint.setColor(Color.BLUE)canvas.drawPoints(pts, 0, 16, mPaint)
//3.mPaint.setColor(Color.GREEN)offset = 100pts = floatArrayOf(500f + offset, 100f, 500f + offset, 200f,500f + offset, 300f, 500f + offset, 600f,500f + offset, 700f, 500f + offset, 800f,500f + offset, 900f, 500f + offset, 1000f)canvas.drawPoints(pts, mPaint)复制代码
效果如下:
绘制矩形
RectF :保存 float 矩形结构
Rect:保存 int 矩形结构
这里会用到 View 坐标点的知识,对 left,top,right,bottom 还不熟悉的可以参考 高级 UI 成长之路 (一) View 的基础知识你必须知道
//1.void drawRect(@NonNull RectF rect, @NonNull Paint paint) {super.drawRect(rect, paint);//2.void drawRect(@NonNull Rect r, @NonNull Paint paint)//3.void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint)
//1.var rect = RectF(100.50f,100.50f,500.50f,500.50f)mPaint.style = Paint.Style.FILLcanvas.drawRect(rect,mPaint)
//2.
var rect2 = Rect(300,300,600,600)mPaint.style = Paint.Style.FILLmPaint.setColor(Color.BLUE)mPaint.alpha = 100canvas.drawRect(rect2,mPaint)
//3.mPaint.style = Paint.Style.FILLmPaint.setColor(Color.YELLOW)canvas.drawRect(500f,500f,1000f,1000f,mPaint)
效果如下:
绘制路径
//根据 path 绘制路径 void drawPath(@NonNull Path path, @NonNull Paint paint)
/**
1. 绘制路径线*/var path = Path()//1. 设置起始点 path.moveTo(100f, 100f)//2. 第二条线的起点就是 moveTo 设置的启动 path.lineTo(100f,300f)//3. 第三条线的起点就是第二条的终点,依次类推 path.lineTo(300f,500f)path.lineTo(500f,200f)//4. 闭合 path.close()canvas.drawPath(path, mPaint)
/**
2. 绘制弧度路径*/var path2 = Path()//绘制弧度的起始位置 path2.moveTo(100f,600f)var rectF = RectF(100f,600f,600f,1000f)//第一个参数生成椭圆的矩形,第二个参数是弧开始的角度以 X 轴正方向为 0 度,第三个参数是弧持续的角度 path2.arcTo(rectF,0f,90f)canvas.drawPath(path2, mPaint)
上面注释很详细,就不在解释了
绘制圆/椭圆
//绘制椭圆 void drawOval(@NonNull RectF oval, @NonNull Paint paint)//绘制圆 void drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
/**
1. 绘制椭圆*/canvas.drawOval(RectF(100f,500f,600f,800f),mPaint)
/**
2. 绘制圆*/mPaint.setColor(Color.YELLOW)mPaint.alpha = 100canvas.drawCircle(400f,400f,200f,mPaint)
绘制 Bitmap
//val bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.gild_3)//第二个,第三个参数代表起点位置 canvas.drawBitmap(bitmap,100f,100f,mPaint)
绘制 Text
//1.void drawText(@NonNull char[] text, int index, int count, float x, float y,@NonNull Paint paint)//2.void drawText(@NonNull String text, float x, float y, @NonNull Paint paint)//3.void drawText(@NonNull String text, int start, int end, float x, float y,@NonNull Paint paint)//4.void drawText(@NonNull CharSequence text, int start, int end, float x, float y,@NonNull Paint paint)
/**
取 0 ~ 5 位置的 text 进行绘制*/mPaint.textSize = 100fcanvas.drawText(charArrayOf('1','2','3','4','5'),0,5,200f,200f,mPaint)
/**
*/canvas.drawText("12345",300f,300f,mPaint)
/**
3.取 0 ~ 5 位置的 text 进行绘制*/canvas.drawText("12345",0,5,400f,400f,mPaint)
根据路径绘制 Text
//从 hOffset 向外偏移 vOffset px 来绘制 textvoid drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,float vOffset, @NonNull Paint paint)复制代码
mPaint.setColor(Color.GREEN)mPaint.alpha = 100
mPaint.textSize = 100fvar path = Path()//1. 设置起始点 path.moveTo(300f, 300f)//2. 第二条线的起点就是 moveTo 设置的启动 path.lineTo(300f,500f)//3. 第三条线的起点就是第二条的终点,依次类推 path.lineTo(500f,800f)path.lineTo(800f,200f)//4. 闭合 path.close()canvas.drawPath(path,mPaint)//从 0 偏移 100px 的像素 canvas.drawTextOnPath("12345asodnaspdnfpoashfeuinfapjn",path,0f,100f,mPaint)
绘制 弧/扇形
//1.void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,@NonNull Paint paint)//2.void drawArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean useCenter, @NonNull Paint paint)
var rectF = RectF(100f, 100f, 500f, 500f)/**
1. 绘制弧
@param ovar : 矩形坐标
@param startAngle : 开始的角度
@param sweepAngle : 结束的角度
@param userCenter : 如果为 true,则将椭圆的中心包括在圆弧中
@param paint : 画笔*/canvas.drawArc(rectF, 0f, 90f, true, mPaint)
/**
2. 绘制弧*/canvas.drawArc(100f,500f,500f,900f,0f,90f,false,mPaint)
绘制圆角矩形
//1.void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)//2.void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,@NonNull Paint paint)
/**
1. 根据 RectF 绘制圆角矩形
@param rx: x 轴上的圆角半径
@param ry: y 轴上的圆角半径/canvas.drawRoundRect(rectF,50f,50f,mPaint)/*
2. 根据输入矩形位置绘制圆角矩形*/canvas.drawRoundRect(100f,600f,500f,900f,100f,100f,mPaint)
Canvas 变换
translate - 图层平移
//dx/dy:x/y 点新位置 void translate(float dx, float dy)
scale- 图层缩小 0~1
//x,y 缩小系数 0~1 之间 越大说明越接近原始图像 void scale(float sx, float sy)复制代码
/**
1. 原始矩形*/mPaint.color = Color.REDmPaint.alpha = 100canvas.drawRoundRect(rectF,50f,50f,mPaint)
/**
2.将原始图形缩小 0.5 倍*/var rectF2 = RectF(100f, 100f, 500f, 500f)mPaint.color = Color.BLUEmPaint.alpha = 100canvas.scale(0.5f,0.5f)canvas.drawRoundRect(rectF2,50f,50f,mPaint)
rotate - 图层旋转
//1.void rotate(float degrees)//2.void rotate(float degrees, float px, float py)
/**
1. 原始矩形*/mPaint.color = Color.REDmPaint.alpha = 100canvas.drawRoundRect(rectF,50f,50f,mPaint)
/**
2.将原始图形旋转 45°*/mPaint.color = Color.BLUEmPaint.alpha = 100canvas.rotate(45f)canvas.drawRoundRect(rectF,50f,50f,mPaint)
/**
3.将原始图形旋转 280°
以 坐标点 500,100 顺时针旋转 280°*/mPaint.color = Color.YELLOWmPaint.alpha = 100canvas.rotate(280f,500f,100f)canvas.drawRoundRect(rectF,50f,50f,mPaint)
skew - 图层错切
//错切是在某方向上,按照一定的比例对图形的每个点到某条平行于该方向的直线的有向距离做放缩得到的平面图形。水平错切(或平行于 X 轴的错切)是一个将任一点(x,y)映射到点(x+my,y)的操作,m 是固定参数,称为错切因子//sx 和 sy 分就是错切因子,为倾斜角度 tan 值,这里倾斜 45 度值为 1void skew (float sx, float sy)
/**
1. 原始图形/mPaint.color = Color.REDmPaint.alpha = 100canvas.drawRoundRect(rectF,50f,50f,mPaint)/*
2.图层开始错切*/canvas.skew(0f,0.5f)mPaint.color = Color.BLUEmPaint.alpha = 100canvas.drawRoundRect(rectF,50f,50f,mPaint)
Matrix
/**
原始图形/canvas.drawBitmap(mBitmap,100f,100f,mPaint)/**1. 矩阵平移 500,500*/var matrix = Matrix()matrix.setTranslate(500f,500f)canvas.drawBitmap(mBitmap,matrix,mPaint)
/**
2. 矩阵缩放 0.5 倍*/var matrix2 = Matrix()matrix2.setScale(0.5f,0.5f)canvas.drawBitmap(mBitmap,matrix2,mPaint)
/**
3. 矩阵旋转 125°*/var matrix3 = Matrix()matrix3.setRotate(125f,500f,500f)canvas.drawBitmap(mBitmap,matrix3,mPaint)
/**
4. 错切*/var matrix4 = Matrix()matrix4.setSkew(0.5f,0.5f)canvas.drawBitmap(mBitmap,matrix4,mPaint)
裁剪画布
//裁剪 boolean?clipRect(RectF?rect,?Region.Op?op);boolean?clipRect(Rect?rect,?Region.Op?op);boolean?clipRect(RectF?rect);boolean?clipRect(Rect?rect);boolean?clipRect(float?left,?float?top,?float?right,?float?bottom,?Region.Op?op);boolean?clipRect(float?left,?float?top,?float?right,?float?bottom);boolean?clipRect(int?left,?int?top,?int?right,?int?bottom);boolean?clipPath(Path?path,?Region.Op?op);boolean?clipPath(Path?path);boolean?clipRegion(Region?region,?Region.Op?op);boolean?clipRegion(Region?region);
上图中的 1 代表原始的图层,未被裁剪;2 代表已经裁剪了的图层;3,不管怎么绘制只能在该区域内部绘制。
/**
1. 原始图形/mPaint.color = Color.REDmPaint.alpha = 100canvas.drawRect(300f,300f,700f,700f,mPaint)canvas.drawText("1.原始",400f,600f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 100fit.color = Color.WHITE})/*
2. 在 RectF 矩形区域裁剪一块画布,绘制图形只能在该区域中绘制*/var rectf2 = RectF(100f, 100f , 500f, 500f);canvas.clipRect(rectf2)mPaint.color = Color.BLUEmPaint.alpha = 100canvas.drawColor(mPaint.color)canvas.drawText("2.clip",200f,200f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 100fit.color = Color.WHITE})
/**
3. 在 300,300;700,700 坐标点上绘制矩形*/mPaint.color = Color.YELLOWmPaint.alpha = 100canvas.drawRect(300f,300f,700f,700f,mPaint)canvas.drawText("3.裁剪之后",350f,400f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 30fit.color = Color.WHITE})
画布的保存与恢复
save 和 restore 一般成对的出现,save 可以保存 canvas 当前的状态,随后进行平移,裁剪等一系列改变 canvas 的操作,最后使用 restore 将 canvas 还原成 save 时候的状态。
int save() //每次调用该函数,都会保存当前画布状态,将其放入特定的栈中 void restore() //从栈顶去除这个状态,对画布进行恢复
通过在未裁剪的时候先调用 canvas.save 保存图层,裁剪完之后在调用 canvas.restore 来恢复之前的图层
/**
1. 原始图形/mPaint.color = Color.REDmPaint.alpha = 100canvas.drawRect(300f,300f,700f,700f,mPaint)canvas.drawText("1.原始",400f,600f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 100fit.color = Color.WHITE})/*
2. 在 RectF 矩形区域裁剪一块画布,绘制图形只能在该区域中绘制*/var rectf2 = RectF(100f, 100f , 500f, 500f);//将未裁剪的图层先进行保存 canvas.save()canvas.clipRect(rectf2)mPaint.color = Color.BLUEmPaint.alpha = 100canvas.drawColor(mPaint.color)canvas.drawText("2.clip",200f,200f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 100fit.color = Color.WHITE})
/**
3. 在 300,300;700,700 坐标点上绘制矩形*///裁剪完之后出栈 canvas.restore()mPaint.color = Color.YELLOWmPaint.alpha = 100canvas.drawRect(300f,300f,600f,600f,mPaint)canvas.drawText("3.裁剪之后",350f,400f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 30fit.color = Color.WHITE})
Canvas 与图层
上一小节介绍了 save,restore 可以用来保存图层,下面在来介绍几个 API 同样也可以用于保存图层
//bounds:要保存的区域所对应的举行对象//saveFlags:取值 ALL_SAVE_FLAG 表示保存全部内容 public int saveLayer(RectF bounds,Paint paint,int saveFlags)public int saveLayer(float left,float top,float right,float bottom,Paint paint,int saveFlags)
上图的意思是绘制一个以红色的裁剪区域,然后在绘制一个圆可看图中注释 2 ,发现只能在裁剪区域绘制了,但是如果调用 canvas.restoreToCount 之后在绘制,就不会受影响了可看图中注释 3 区域。
/**
1. 原始图像/mPaint.color = Color.REDmPaint.alpha = 200canvas.drawRect(300f,300f,1000f,1000f,mPaint)canvas.drawText("1. 裁剪图层",750f,750f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 30fit.color = Color.WHITE})/*
2. 保存*/val saveLayer = canvas.saveLayer(300f, 300f, 1000f, 1000f, mPaint,ALL_SAVE_FLAG)mPaint.color = Color.BLUEmPaint.alpha = 100canvas.drawCircle(500f,500f,300f,mPaint)canvas.drawText("2. 绘制圆",350f,700f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 30fit.color = Color.WHITE})
/**
3.恢复图层/canvas.restoreToCount(saveLayer)/*
*/mPaint.color = Color.BLUEmPaint.alpha = 100canvas.drawCircle(400f,400f,200f,mPaint)canvas.drawText("3. 恢复",350f,250f,Paint(Paint.ANTI_ALIAS_FLAG).also {it.textSize = 30fit.color = Color.WHITE})
Canvas 基础常用的 API 这里都练习了一遍,下面就进行该篇最后的环节了,以一个示例 demo 结束 Canvas 的讲解。
评论