笔记—自定义View之Canvas对绘制的辅助

来源:互联网 发布:平泽唯 知乎 编辑:程序博客网 时间:2024/04/29 13:42

一 范围裁切

1 Canvas.clipRect(Rect rect) 按传入的矩形剪切

canvas.save()val bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.batman)val rect = RectF(100f, 100f, 600f, 600f)canvas.clipRect(rect)canvas.drawBitmap(bitmap1, 0f, 0f, Paint())canvas.restore()

2 Canvas.clipPath(Path path) 按传入的路径剪切

val bitmap2 = BitmapFactory.decodeResource(resources, R.drawable.batman)canvas.save()val path = Path()path.addCircle(600f, 600f, 200f, Path.Direction.CW)canvas.clipPath(path)canvas.drawBitmap(bitmap2, 0f, 0f, Paint())anvas.restore()

二 几何变换

1 使用Canvas做常见的二维变换

1 Canvas.translate(dx,dy) 移动 参数里的 dx 和 dy 表示横向和纵向的位移

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)canvas.save()canvas.translate(200f, 0f)canvas.drawBitmap(bitmap, 0f, 0f, Paint())canvas.restore()

2 canvas.rotate(degress,px,py) 旋转 参数里的 degrees 是旋转角度,单位是度(也就是一周有 360° 的那个单位),方向是顺时针为正向; px 和 py 是轴心的位置。

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)canvas.save()canvas.rotate(180f, 300f, 300f)canvas.drawBitmap(bitmap, 0f, 0f, Paint())canvas.restore()

3 canvas.scale(sx,sy,px,py)缩放 参数里的 sx sy 是横向和纵向的放缩倍数; px py 是放缩的轴心

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)canvas.save()canvas.scale(1.3f, 1.3f, bitmap.width.toFloat() / 2, bitmap.height.toFloat() / 2)canvas.drawBitmap(bitmap, 0f, 0f, Paint())canvas.restore()

4 canvas.skew(sx,sy) 错切 参数里的 sx 和 sy 是 x 方向和 y 方向的错切系数。

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)canvas.save()canvas.skew(-0.5f, 0f)canvas.drawBitmap(bitmap, 0f, 0f, Paint())canvas.restore()

5 混合变换 需要注意的是 变换动作需要倒叙 需要的效果是 平移 之后 旋转45度 代码如下

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)canvas.save()canvas.rotate(45f, 0f, 0f)canvas.translate(100f, 0f)canvas.drawBitmap(bitmap, 0f, 0f, Paint())canvas.restore()

2 使用Matrix做常见和不常见的二维变换 Matrix 的中文是矩阵的意思 背后的原理 是大学的代数

1 使用 Matrix 来做常见变换

第一步:创建 Matrix 对象 Matrix matrix = new Matrix();第二步:调用 Matrix 的 pre/postTranslate/Rotate/Scale/Skew() 方法来设置几何变换 pre是倒叙插入 post是正序插入 变换方法对应上面第三步:使用 Canvas.setMatrix(matrix) 或 Canvas.concat(matrix) 来把几何变换应用到 Canvas。Canvas.setMatrix(matrix):用 Matrix 直接替换 Canvas 当前的变换矩阵,即抛弃 Canvas 当前的变换,改用 Matrix 的变换(注:根据下面评论里以及我在微信公众号中收到的反馈,不同的系统中 setMatrix(matrix) 的行为可能不一致,所以还是尽量用 concat(matrix) 吧);Canvas.concat(matrix):用 Canvas 当前的变换矩阵和 Matrix 相乘,即基于 Canvas 当前的变换,叠加上 Matrix 中的变换。val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)val matrix = Matrix()matrix.postRotate(45f)matrix.preTranslate(100f, 0f)canvas.save()canvas.matrix = matrixcanvas.drawBitmap(bitmap, 0f, 0f, Paint())canvas.restore()

2 使用Matrix做自定义二维变换 Matrix 的自定义变换使用的是 setPolyToPoly() 方法

Matrix.setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) 用点对点映射的方式设置变换poly 就是「多」的意思。setPolyToPoly() 的作用是通过多点的映射的方式来直接设置变换。「多点映射」的意思就是把指定的点移动到给出的位置,从而发生形变。例如:(0, 0) -> (100, 100) 表示把 (0, 0) 位置的像素移动到 (100, 100) 的位置,这个是单点的映射,单点映射可以实现平移。而多点的映射,就可以让绘制内容任意地扭曲。Matrix matrix = new Matrix();float pointsSrc = {left, top, right, top, left, bottom, right, bottom};float pointsDst = {left - 10, top + 50, right + 120, top - 90, left + 20, bottom + 30, right + 20, bottom + 60};matrix.reset();matrix.setPolyToPoly(pointsSrc, 0, pointsDst, 0, 4);canvas.save();canvas.concat(matrix);canvas.drawBitmap(bitmap, x, y, paint);canvas.restore();参数里,src 和 dst 是源点集合目标点集;srcIndex 和 dstIndex 是第一个点的偏移;pointCount 是采集的点的个数(个数不能大于 4,因为大于 4 个点就无法计算变换了)。

3 使用Camera做三维变换

1 Camera.rotate*() 三维旋转 就是设置相机 沿xyz轴旋转 Camera.rotate*() 一共有四个方法: rotateX(deg) rotateY(deg) rotateZ(deg) rotate(x, y, z)

canvas.save();camera.save(); // 保存 Camera 的状态camera.rotateX(30); // 旋转 Camera 的三维空间camera.applyToCanvas(canvas); // 把旋转投影到 Canvascamera.restore(); // 恢复 Camera 的状态canvas.drawBitmap(bitmap, point1.x, point1.y, paint);canvas.restore();如果你需要图形左右对称,需要配合上 Canvas.translate(),在三维旋转之前把绘制内容的中心点移动到原点,即旋转的轴心,然后在三维旋转后再把投影移动回来:canvas.save();camera.save(); // 保存 Camera 的状态camera.rotateX(30); // 旋转 Camera 的三维空间canvas.translate(centerX, centerY); // 旋转之后把投影移动回来camera.applyToCanvas(canvas); // 把旋转投影到 Canvascanvas.translate(-centerX, -centerY); // 旋转之前把绘制内容移动到轴心(原点)camera.restore(); // 恢复 Camera 的状态canvas.drawBitmap(bitmap, point1.x, point1.y, paint);canvas.restore();Canvas 的几何变换顺序是反的,所以要把移动到中心的代码写在下面,把从中心移动回来的代码写在上面。val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)canvas.save()val camera = Camera()camera.save()camera.rotateX(30f)canvas.translate(bitmap.width.toFloat() / 2, bitmap.height.toFloat() / 2)camera.applyToCanvas(canvas)canvas.translate(-bitmap.width.toFloat() / 2, -bitmap.height.toFloat() / 2)camera.restore()canvas.drawBitmap(bitmap, 0f, 0f, Paint())canvas.restore()

2 Camera.translate(float x, float y, float z) 移动 它的使用方式和 Camera.rotate*() 相同

3 Camera.setLocation(x, y, z) 设置虚拟相机的位置 一般设置 z 轴上的位置 x y 设置为0

注意!这个方法有点奇葩,它的参数的单位不是像素,而是 inch,英寸 英寸和像素的换算单位在 Skia 中被写死为了 72 像素
在 Camera 中,相机的默认位置是 (0, 0, -8)(英寸)。8 x 72 = 576,所以它的默认位置是 (0, 0, -576)(像素)。

原创粉丝点击