前言
裁剪和几何变换,说实话平时用到的也不多,但确实也是很有意思的内容,一起来看一下吧
范围裁切
// 裁剪一个矩形
canvas.save();
canvas.clipRect(left, top, right, bottom);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
// 裁剪一个Path, 能裁剪的形状更多一些
canvas.save();
canvas.clipPath(path);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
几何变换
几何变换使用大概分为三类:
- 使用Canvas来做常见的二维变换
- 使用Matrix来做常见和不常见的二维变换
- 使用Camera来做三维变换
//1、使用Canvas来做常见的二维变换
// 格式
canvas.save();
canvas.tranlate(200, 0);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
// 平移
canvas.tranlate(x, y);
// 旋转
canvas.tranlate(degrees, centerX, centerY);
// 缩放
canvas.scale(sx, sy, centerX, centerY);
// 错切
canvas.skew(sx, sy)
//2、使用Matrix
// 常见变换
Matrix matrix = new Matrix();
matrix.reset();
matrix.postXXX();
canvas.concat(matrix);
// 自定义变换,通过点对点映射的方式设置变换,多点的映射,可以让绘制内容任意的扭曲
matrix.setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
使用Camera来做三维变换
Camera的坐标系:X右正,Y上正,Z向内正
Camera在Z轴负方向上,也就是说始终在原点的Z轴上,往View上做一个投影
Camera旋转方向:
// camera.rotateX() 使用方法:
// 这个投影会是斜的,因为没有将canvas平移至原点
canvas.save();
camera.save();
camera.rotateX(30);
camera.applyToCanvas(canvas);
camera.restore();
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 需要在三维旋转之前将绘制内容的中心点移动到原点,投影后再移动回来
// canvas的几何变换顺序是反的,所以要把移到原点的代码写在下面,从中心移动回来的代码写在上面
canvas.save();
camera.save();
camera.rotateX(30);
canvas.tranlate(centerX, centerY);
camera.applyToCanvas(canvas);
canvas.tranlate(-centerX, -centerY);
camera.restore();
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// Camera.translate()很少用到这个
// Camera.setLocation(x, y, z);
x,y一般不会变,z默认是-8,默认位置是8 x 72 = 576像素,往后移动可以修复糊脸问题
总结
1、范围裁切,可以裁切Rect或者任意的Path
2、二维变换:canvas可以做常见的二维变换,matrix可以做不常见的二维变换
3、三维变换:使用Camera来投影
贴个HenCoder的链接:自定义View-Canvas对绘制的辅助clipXXX()和Matrix
分割线---------------------------------------------------------------------------
实践
// 1 裁剪一个矩形出来
int left = (getWidth() - bitmap.getWidth()) / 2;
int top = (getHeight() - bitmap.getHeight()) / 2;
canvas.save();
canvas.clipRect(left + 50, top + 50, left + 300, left + 100);
canvas.drawBitmap(bitmap, left, top, paint);
canvas.restore();
// 2 裁剪一个圆和取圆相反的图形
// add一个圆, 顺时针
path1.addCircle(point1.x + 200, point1.y + 200, 150, Path.Direction.CW);
canvas.save();
canvas.clipPath(path1);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 取相反的图形
path2.setFillType(Path.FillType.INVERSE_WINDING);
path2.addCircle(point2.x + 200, point2.y + 200, 150, Path.Direction.CW);
canvas.save();
canvas.clipPath(path2);
canvas.drawBitmap(bitmap, point2.x, point2.y, paint);
canvas.restore();
// 3 向右平移canvas, 200像素
canvas.save();
canvas.translate(200, 0);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 4 缩放canvas, x, y都扩大为原来的1.2倍
int centerX1 = point1.x + bitmap.getWidth() / 2;
int centerY1 = point1.y + bitmap.getHeight() / 2;
canvas.save();
canvas.scale(1.2f, 1.2f, centerX1, centerY1);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 5 旋转canvas, 旋转180度
int centerX1 = point1.x+ bitmap.getWidth() / 2;
int centerY1 = point1.y+ bitmap.getHeight() / 2;
canvas.save();
canvas.rotate(180, centerX1, centerY1);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 6 错切canvas, y错切0.5
canvas.save();
canvas.skew(0, 0.5f);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 7 向右平移matrix, 200像素
canvas.save();
matrix.reset();
matrix.postTranslate(200, 0);
canvas.concat(matrix);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 8 缩放matrix, x, y都扩大为原来的1.2倍
int centerX1 = point1.x + bitmap.getWidth() / 2;
int centerY1 = point1.y + bitmap.getHeight() / 2;
canvas.save();
matrix.reset();
matrix.postScale(1.2f, 1.2f, centerX1, centerY1);
canvas.concat(matrix);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 9 旋转matrix, 旋转180度
int centerX1 = point1.x + bitmap.getWidth() / 2;
int centerY1 = point1.y + bitmap.getHeight() / 2;
canvas.save();
matrix.reset();
matrix.postRotate(180, centerX1, centerY1);
canvas.concat(matrix);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 10 错切matrix, y错切0.5
canvas.save();
matrix.reset();
matrix.postSkew(0, 0.5f);
canvas.concat(matrix);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 11 Camera在原点, 旋转图形, 沿x轴旋转30度后直接投影
canvas.save();
camera.save();
camera.rotateX(30);
camera.applyToCanvas(canvas);
camera.restore();
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 12 修正版, Camera在原点, 旋转图形, 沿x轴旋转30度后, 将图形移到原点投影后再移回来
int centerX1 = point1.x + bitmapWidth / 2;
int centerY1 = point1.y + bitmapHeight / 2;
camera.save();
matrix.reset();
camera.rotateX(30);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX1, -centerY1);
matrix.postTranslate(centerX1, centerY1);
canvas.save();
canvas.concat(matrix);
canvas.drawBitmap(bitmap, point1.x, point1.y, paint);
canvas.restore();
// 13 沿x轴旋转,糊脸修正
// 通过属性动画, 改变degree属性
// 注意设置camera的setLocation()方法设置距离Z轴的高度
// onDraw() 方法中是Camera三维变换的代码
// 14 翻页效果,下半部分翻页
// 设置动画代码省略
// 关键代码
// 算出几个重要的坐标点
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
// 中心点
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
// 图片左上角原点
int x = centerX - bitmapWidth / 2;
int y = centerY - bitmapHeight / 2;
// 首先绘制上半部分
canvas.save();
canvas.clipRect(0, 0, getWidth(), centerY);
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();
// 绘制下半部分的旋转
canvas.save();
if (degree < 90) {
// 旋转角度小于90,裁剪下半部分
canvas.clipRect(0, centerY, getWidth(), getHeight());
} else {
// 旋转角度大于90,裁剪上半部分
canvas.clipRect(0, 0, getWidth(), centerY);
}
camera.save();
camera.rotateX(degree);
canvas.translate(centerX, centerY);
camera.applyToCanvas(canvas);
canvas.translate(-centerX, -centerY);
camera.restore();
canvas.drawBitmap(bitmap, x, y, paint);
canvas.restore();