Android绘图之Canvas变换(6)

Android 绘图学习

1 Canvas 与屏幕

前面讲解了Canvas的基本概念,Android绘图之Canvas概念理解(5)
对Canvas的概念进行了分析,但是没有说明和屏幕的关系,Canvas不等于屏幕,屏幕不会动的,我们也无法对屏幕进行(平移,缩放等)操作,只能对Canvas进行操作,所以对Canvas进行操作,屏幕不动,最终会导致看到的图像不同。

下面开始讲解Canvas的变幻操作:
包括:translate,rotate,scale,skew,clip,clipout,matrix

2 translate 平移

先从最简单的平移开始:

/**
 * 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) {
    if (dx == 0.0f && dy == 0.0f) return;
    nTranslate(mNativeCanvasWrapper, dx, dy);
}

对Canvas进行平移,
dx: x轴方向进行平移,正值向屏幕右侧
dy:y轴方向进行平移,正值向屏幕下方

mPaint1.setStrokeWidth(50);
canvas.drawPoint(0,0,mPaint1);
mPaint1.setColor(Color.RED);
canvas.translate(300,300);
canvas.drawPoint(0,0,mPaint1);

绘制两个点查看原点位置。


//绘制矩形:
canvas.drawRect(200,200,700,700,mPaint1);
mPaint1.setColor(Color.RED);
canvas.translate(200,200);
canvas.drawPoint(0,0,mPaint1);
canvas.drawRect(200,200,700,700,mPaint1);

mPaint1.setColor(Color.GRAY);
canvas.drawRect(300,300,800,800,mPaint1);

原点显然改变了,以后再绘制任何形状都是以translate后的原点开始绘制。

3 scale 缩放

/**
 * 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) {
    if (sx == 1.0f && sy == 1.0f) return;
    nScale(mNativeCanvasWrapper, sx, sy);
}

/**
 * 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);
}

参数说明
sx:横向的缩放,默认为1,小数缩小,整数放大
sy:纵向的缩放,默认为1,小数缩小,整数放大

px,py,看源码知道是先translate,执行sx,sy然后再translate反方向。
第二次translate的坐标为(-pxsx,-pxsy),最终的效果就是px,py是缩放后不动的点。

canvas.drawRect(200,200,700,700,mPaint1);
canvas.scale(0.5f,0.5f);
mPaint1.setColor(Color.GRAY);
canvas.drawRect(200,200,700,700,mPaint1);

缩放后坐标减半。

如果想控制缩放后的位置,如何控制呢,这就需要第二个函数。

canvas.drawRect(200,200,700,700,mPaint1);
canvas.scale(0.5f,0.5f,200,200);
mPaint1.setColor(Color.GRAY);
canvas.drawRect(200,200,700,700,mPaint1);

还可以控制其他位置,例如控制缩放后在中心。

canvas.drawRect(200,200,700,700,mPaint1);
canvas.scale(0.5f,0.5f,450,450);
mPaint1.setColor(Color.GRAY);
canvas.drawRect(200,200,700,700,mPaint1);

4 Canvas 的旋转rotate

/**
 * Preconcat the current matrix with the specified rotation.
 *
 * @param degrees The amount to rotate, in degrees
 */
public void rotate(float degrees) ;
/** *
 * @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);
}

rotate有两个函数:
rotate(float degrees)
rotate(float degrees, float px, float py)
Degree:旋转的角度,正值为顺时针,负值为逆时针
Px,py:旋转的中心,如果不指定旋转中心默认为(0,0)点

canvas.drawRect(400,400,900,900,mPaint1);
canvas.rotate(-10);
mPaint1.setColor(Color.GRAY);
canvas.drawRect(400,400,900,900,mPaint1);

指定旋转中心为矩形中心

canvas.drawRect(400,400,900,900,mPaint1);
canvas.drawPoint(100,100,mPaint1);
canvas.rotate(10,650,650);

mPaint1.setColor(Color.GRAY);
canvas.drawRect(400,400,900,900,mPaint1);

5 Skew 倾斜 画布

/**
 * Preconcat the current matrix with the specified skew.
 *
 * @param sx The amount to skew in X
 * @param sy The amount to skew in Y
 */
public void skew(float sx, float sy) {
    if (sx == 0.0f && sy == 0.0f) return;
    nSkew(mNativeCanvasWrapper, sx, sy);
}

参数说明:
sx:画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
sy:画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值,

canvas.drawRect(200,200,700,700,mPaint1);
canvas.save();
canvas.skew(tan(30),0);
mPaint1.setColor(Color.GRAY);
canvas.drawRect(200,200,700,700,mPaint1);
canvas.restore();
mPaint1.setColor(Color.BLUE);
canvas.drawRect(200,800,700,1300,mPaint1);
canvas.save();
canvas.skew(0,tan(30));
mPaint1.setColor(Color.GRAY);
canvas.drawRect(200,800,700,1300,mPaint1);
canvas.restore();

public float tan(int degree){
   return (float) Math.tan(degree*1.0/180*Math.PI);
}

6 clip 切割画布

根据矩形或者路径裁剪画布,画布被切割之后,只有部分区域可用,其他区域无法绘制内容。
Clip函数切割的区域可用,clipOut未被切割的区域可用。(过时函数不再讲解)

clipRect(@NonNull RectF rect)
clipRect(@NonNull Rect rect)
clipRect(float left, float top, float right, float bottom)
clipRect(int left, int top, int right, int bottom)

clipPath(@NonNull Path path)

一下函数需要api26以上
clipOutRect(@NonNull RectF rect)
clipOutRect(@NonNull Rect rect)
clipOutRect(float left, float top, float right, float bottom)
clipOutRect(int left, int top, int right, int bottom)
clipOutPath(@NonNull Path path)

canvas.drawRect(200,200,700,700,mPaint1);
mPaint1.setColor(Color.GRAY);
canvas.drawRect(200,800,700,1300,mPaint1);
canvas.clipRect(200, 200, 700, 700);//截取画布大小为
canvas.drawCircle(100,100,100,mPaint1);//画布被剪切,无法画上
canvas.drawCircle(300,300,100,mPaint1);//可以画上
canvas.drawRect(200,200,700,700,mPaint1);
mPaint1.setColor(Color.GRAY);
canvas.drawRect(200,800,700,1300,mPaint1);
canvas.clipOutRect(200, 200, 700, 700);//截取画布大小为
canvas.drawCircle(100,100,100,mPaint1);//可以画上
canvas.drawCircle(300,300,100,mPaint1);//无法画上

7 matrix 变换

Matrix提供了一些方法来控制变换:

setTranslate(float dx,float dy):平移操作
setSkew(float kx,float ky):skew操作
setSkew(float kx,float ky,float px,float py):
setRotate(float degrees):旋转
setRotate(float degrees,float px,float py):
setScale(float sx,float sy):缩放
setScale(float sx,float sy,float px,float py):

Matrix的pre XXX和postXXX是左乘右乘的区别,是为了组合各种操作,因为矩阵不符合交换率,所以左乘右乘效果不同,一般利用matrix的效果需要反着乘得到最终的matrix.
以上的效果和canvas的set操作效果一样。

canvas.drawRect(200,200,700,700,mPaint1);
mPaint1.setColor(Color.GRAY);
Matrix matrix = new Matrix();
matrix.setRotate(10);
canvas.setMatrix(matrix);
canvas.drawRect(200,200,700,700,mPaint1);

android绘图之Paint(1)
android绘图之Canvas基础(2)
Android绘图之Path(3)
Android绘图之drawText绘制文本相关(4)
Android绘图之Canvas概念理解(5)
Android绘图之Canvas变换(6)
Android绘图之Canvas状态保存和恢复(7)
Android绘图之PathEffect (8)
Android绘图之LinearGradient线性渐变(9)
Android绘图之SweepGradient(10)
Android绘图之RadialGradient 放射渐变(11)
Android绘制之BitmapShader(12)
Android绘图之ComposeShader,PorterDuff.mode及Xfermode(13)
Android绘图之drawText,getTextBounds,measureText,FontMetrics,基线(14)
Android绘图之贝塞尔曲线简介(15)
Android绘图之PathMeasure(16)
Android 动态修改渐变 GradientDrawable

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,873评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,483评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,525评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,595评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,018评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,958评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,118评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,873评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,643评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,813评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,293评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,615评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,306评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,170评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,968评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,107评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,894评论 2 278

推荐阅读更多精彩内容