变换
API | 功能说明 |
---|---|
translate(dx, dy) | 平移操作 |
scale(sx, sy) | 缩放操作 |
rotate(degress) | 旋转操作 |
skew(sx, sy) | 倾斜操作 |
clipXXX() | 切割操作,参数指定区域内可以继续绘制 |
clipOutXXX() | 反向切割操作,参数指定区域内不可以绘制 |
setMatrix(matrix) | 通过Matrix实现平移、缩放、旋转等操作 |
平移
将画布平移,后面绘制的图像都是以平移后为原点
/**
* Preconcat the current matrix with the specified translation
* 平移操作
* @param dx The distance to translate in X
* @param dy The distance to translate in Y
*/
public void translate(float dx, float dy)
/**************************************************/
// eg:平移
mPaint.setColor(Color.RED);
canvas.drawRect(0, 0, 500, 500, mPaint);
canvas.translate(200, 200);
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, 500, 500, mPaint);
mPaint.setColor(Color.GRAY);
canvas.drawLine(0, 0, 600, 600, mPaint);
蓝色为移动画布前,在移动画布后,绘制的矩形和直线都是从(200,200)开始绘制的
缩放
将画布进行倍数缩放
/**
* Preconcat the current matrix with the specified scale.
*
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
*/
public void scale(float sx, float sy)
mPaint.setColor(Color.BLUE);
canvas.drawRect(200, 200, 700, 700, mPaint);
canvas.scale(0.5f, 0.5f);
mPaint.setColor(Color.RED);
canvas.drawRect(200, 200, 700, 700, mPaint);
有重载方法如下,该方法会先平移,再缩放,再反向平移
/**
* Preconcat the current matrix with the specified scale.
*
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
* @param px The x-coord for the pivot point (unchanged by the scale)
* @param py The y-coord for the pivot point (unchanged by the scale)
*/
public final void scale(float sx, float sy, float px, float py) {
if (sx == 1.0f && sy == 1.0f) return;
translate(px, py);
scale(sx, sy);
translate(-px, -py);
}
// eg:
mPaint.setColor(Color.BLUE);
canvas.drawRect(200, 200, 700, 700, mPaint);
//先translate(px,py),在scale(sx, sy), 再反向translate
canvas.scale(0.5f, 0.5f, 200, 200);
mPaint.setColor(Color.RED);
canvas.drawRect(200, 200, 700, 700, mPaint);
上方scale方法等同于
canvas.translate(200,200);
canvas.scale(0.5f, 0.5f);
canvas.translate(-200, -200);
- 左图为基本缩放:可以理解为画布缩放后,所以的左边值都进行缩放后再绘制,比如例子中,缩放0.5以后,绘制的200,就是100,因此看起来不仅矩形变小,也向原点移动了
右图为带坐标缩放,做的是先移动到指定位置,缩放后再平移回来,可以理解成在在指定位置开始缩放。
旋转
将画布参照原点(默认0, 0)顺时针旋转,旋转后绘制
如果画布平移,那么原点就是平移后的原点
/**
* Preconcat the current matrix with the specified rotation.
*
* @param degrees The amount to rotate, in degrees
*/
public void rotate(float degrees)
//eg
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, 500, 500, mPaint);
canvas.rotate(30);
mPaint.setColor(Color.RED);
canvas.drawRect(0, 0, 500, 500, mPaint);
有重载方法,可设定旋转中心(px, py)
/**
* Preconcat the current matrix with the specified rotation.
*
* @param degrees The amount to rotate, in degrees
* @param px The x-coord for the pivot point (unchanged by the rotation)
* @param py The y-coord for the pivot point (unchanged by the rotation)
*/
public final void rotate(float degrees, float px, float py) {
if (degrees == 0.0f) return;
translate(px, py);
rotate(degrees);
translate(-px, -py);
}
//eg:设定旋转中心为矩形中心
mPaint.setColor(Color.BLUE);
canvas.translate(300, 300);
canvas.drawRect(0, 0, 500, 500, mPaint);
canvas.rotate(45, 250, 250); // px, py 旋转中心坐标
mPaint.setColor(Color.RED);
canvas.drawRect(0, 0, 500, 500, mPaint);
- 左图效果是绕着原点旋转
右图为重载函数,设置旋转旋转坐标为矩形中心,旋转45°
倾斜(错切)
sx和sy分别表示将画布在x和y方向上倾斜相应的角度对应的tan值
设置sx 将y逆时针旋转相应角度
设置sy 将x顺时针旋转相应角度
/**
* Preconcat the current matrix with the specified skew.
*
* @param sx The amount to skew in X
* 将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将y逆时针旋转相应的角度
* @param sy The amount to skew in Y
* 将画布在y方向上倾斜相应的角度,sx倾斜角度的tan值,其实就是将x顺时针旋转相应的角度
*/
public void skew(float sx, float sy)
//eg
canvas.translate(200, 200);
mPaint.setColor(Color.BLUE);
mPaint.setTextSize(26);
canvas.drawLine(0, 0, 800, 0, mPaint);//x
canvas.drawText("X", 800, 0, mPaint);
canvas.drawLine(0, 0, 0, 800, mPaint);//y
canvas.drawText("Y", 0, 800, mPaint);
canvas.drawRect(0, 0, 400, 400, mPaint);
// canvas.skew(1, 0);//将画布在x方向上旋转45度,其实就是x轴保持方向不变,y轴逆时针旋转45度
// canvas.skew(0, 1);//将画布在y方向上旋转45度,其实就是y轴保持方向不变,x轴顺时针旋转45度
canvas.skew(1, (float) Math.sqrt(3));// 将画布x方向旋转45,y方向旋转60,可见,x轴顺时针旋转了60度,y逆时针旋转了45度。
mPaint.setColor(Color.DKGRAY);
canvas.drawLine(0, 0, 600, 0, mPaint);//x
canvas.drawText("X", 600, 0, mPaint);
canvas.drawLine(0, 0, 0, 600, mPaint);//y
canvas.drawText("Y", 0, 600, mPaint);
mPaint.setColor(Color.RED);
canvas.drawRect(0, 0, 400, 400, mPaint);
- 左图为 canvas.skew(1, 0) 将画布在x方向上旋转45度,其实就是x轴保持方向不变,y轴逆时针旋转45度
右图为 canvas.skew(0, 1) 将画布在y方向上旋转45度,其实就是y轴保持方向不变,x轴顺时针旋转45度
canvas.skew(1, (float) Math.sqrt(3)) 将画布x方向旋转45,y方向旋转60,可见,x轴顺时针旋转了60度,y逆时针旋转了45度。
切割
clipRect: 将画布切割,后面绘制的在切割范围内可绘制,超出部分不绘制
clipOutRect: 将画布切割,后面绘制的部分在切割范围外可绘制,超出部分不绘制
/**
* Intersect the current clip with the specified rectangle, which is expressed in local coordinates.
*
* @param left The left side of the rectangle to intersect with the current clip
* @param top The top of the rectangle to intersect with the current clip
* @param right The right side of the rectangle to intersect with the current clip
* @param bottom The bottom of the rectangle to intersect with the current clip
* @return true if the resulting clip is non-empty
*/
public boolean clipRect(int left, int top, int right, int bottom)
/**
* Set the clip to the difference of the current clip and the specified rectangle, which is
* expressed in local coordinates.
*
* @param left The left side of the rectangle used in the difference operation
* @param top The top of the rectangle used in the difference operation
* @param right The right side of the rectangle used in the difference operation
* @param bottom The bottom of the rectangle used in the difference operation
* @return true if the resulting clip is non-empty
*/
public boolean clipOutRect(int left, int top, int right, int bottom)
//eg: clipRect切割后,没有显示出完整的圆形,仅在蓝色区域有效,
//clipOutRect:在蓝色矩形外部的部分可显示
mPaint.setColor(Color.BLUE);
canvas.drawRect(100, 100, 500, 500, mPaint);
canvas.clipRect(100, 100, 500, 500);// 画布被裁剪,切割只在该范围有效
// canvas.clipOutRect(100, 100, 500, 500);// 画布裁剪外的区域有效
mPaint.setColor(Color.RED);
canvas.drawCircle(300, 300, 100, mPaint);
- 左图 canvas.clipRect(100, 100, 500, 500); 画布被裁剪,切割只在该范围有效
右图 canvas.clipOutRect(100, 100, 500, 500); 画布裁剪外的区域有效
矩阵Matrix
除了上面的一些变换方法,可以使用Matrix对画布进行变化操作
canvas.setMatrix(matrix);
在Android中Matrix是个3*3的矩阵
通过矩阵也可以实现上述平移旋转等操作,默认单位矩阵为
Matrix 的三种动作:preXXX、postXXX、setXXX
pre/set/postTranslate/Scale/Rotate/Skew
setXXX
setXXX 方法首先会将该Matrix重置为单位矩阵,即相当于首先会调用reset()方法,然后再设置该Matrix中对应功能的值。
mPaint.setColor(Color.BLUE);
canvas.drawRect(100, 100, 500, 500, mPaint);
mPaint.setColor(Color.RED);
Matrix matrix = new Matrix();
Log.d("tina", "matrix:" + matrix.toShortString());
matrix.preScale(0.5f, 0.5f);
Log.d("tina", "matrix scale: " + matrix.toShortString());
matrix.setTranslate(50,50);
Log.d("tina", "matrix translate: " + matrix.toShortString());
canvas.setMatrix(matrix);
canvas.drawRect(100, 100, 500, 500, mPaint);
从示例可看出,矩形并没有缩小,只是平移了,打印的结果如下,也只是改变了负责平移的部分
matrix:[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
matrix scale: [0.5, 0.0, 0.0][0.0, 0.5, 0.0][0.0, 0.0, 1.0]
matrix translate: [1.0, 0.0, 50.0][0.0, 1.0, 50.0][0.0, 0.0, 1.0]
preXXX:
不会重置Matrix,相当于当前操作矩阵(A)左乘参数矩阵(B),即AB。例:
mPaint.setColor(Color.BLUE);
canvas.drawRect(100, 100, 500, 500, mPaint);
mPaint.setColor(Color.RED);
Matrix matrix = new Matrix();
Log.d("tina", "matrix:" + matrix.toShortString());
matrix.preScale(0.5f, 0.5f);
Log.d("tina", "matrix scale: " + matrix.toShortString());
canvas.setMatrix(matrix);
canvas.drawRect(100, 100, 500, 500, mPaint);
matrix:[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
matrix scale: [0.5, 0.0, 0.0][0.0, 0.5, 0.0][0.0, 0.0, 1.0]
可以看到 矩阵的ScaleX和ScaleY 变为了0.5,其实是这么算的,采用的是左乘
postXXX:
不会重置Matrix,相当于当前操作矩阵(A)右乘参数矩阵(B),即BA
mPaint.setColor(Color.BLUE);
canvas.drawRect(100, 100, 500, 500, mPaint);
mPaint.setColor(Color.RED);
Matrix matrix = new Matrix();
Log.d("tina", "matrix init:" + matrix.toShortString());
matrix.setValues(new float[]{4.0f, 0.0f, 100.0f,
0.0f, 4.0f, 100.0f,
0.0f, 0.0f, 1.0f});
Log.d("tina", "matrix set:" + matrix.toShortString());
matrix.postScale(0.5f, 0.5f);
Log.d("tina", "matrix scale: " + matrix.toShortString());
canvas.setMatrix(matrix);
canvas.drawRect(100, 100, 500, 500, mPaint);
我们改变了下单位矩阵,设为如下矩阵,若设置到画布上,表示放大4倍,向x轴平移100,y轴平移100
在此单位矩阵下右乘变换矩阵,得到下方矩阵,在图三表示的就是平移了150(含初始),放大了2倍(其实是初始放大4倍,然后缩放了0.5)
Post:(右图)
matrix init:[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
matrix set:[4.0, 0.0, 100.0][0.0, 4.0, 100.0][0.0, 0.0, 1.0]
matrix scale: [2.0, 0.0, 50.0][0.0, 2.0, 50.0][0.0, 0.0, 1.0]
Set:(左图)
matrix init:[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
matrix set:[4.0, 0.0, 100.0][0.0, 4.0, 100.0][0.0, 0.0, 1.0]
matrix scale: [0.5, 0.0, 0.0][0.0, 0.5, 0.0][0.0, 0.0, 1.0]
Pre:(中图)
matrix init:[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]
matrix set:[4.0, 0.0, 100.0][0.0, 4.0, 100.0][0.0, 0.0, 1.0]
matrix scale: [2.0, 0.0, 100.0][0.0, 2.0, 100.0][0.0, 0.0, 1.0]
状态保存和恢复
save & restore
- save: 保存当前画布状态
- restore: 恢复画布状态
- restoreToCount save 的返回值是一个整形,可以用getSaveCount获取保存的次数,也可以用restoreToCount 恢复某一状态下的画布
int state = canvas.save(); // save和restore可多次使用,每次使用时都是保存/恢复上一次状态 这里会围护一个状态栈
Log.d("tina", "state: " + state); //D/tina: state: 1
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 0, 400, 400, mPaint);
canvas.translate(200,200);
mPaint.setColor(Color.GRAY);
canvas.drawRect(0, 0, 400, 400, mPaint);
canvas.restore();
mPaint.setColor(Color.RED);
canvas.drawLine(0, 0, 300, 300, mPaint);
canvas.getSaveCount(); // 不进行任何操作默认为1 每save一次 加1 没restore一次 减1
canvas.restoreToCount(state); // 恢复到某一次的save内容
saveLayer
saveLayer 创建指定大小的图层,创建图层绘制的形状超过图层到小会被截取
mPaint.setColor(Color.BLUE);
canvas.drawRect(100, 100, 500, 500, mPaint);
int layerId = canvas.saveLayer(0, 0, 500, 500, mPaint); // 创建图层,由于创建图层绘制的形状超过图层到小因此被截取
mPaint.setColor(Color.GRAY);
canvas.translate(100, 100);
canvas.drawRect(100, 100, 600, 600, mPaint);
canvas.restoreToCount(layerId);
mPaint.setColor(Color.RED);
canvas.drawRect(200, 200, 400, 400, mPaint);
网友评论