前言
根據(jù)Gcssloop所學習的自定義View整理與筆記谈喳。
還記得上一篇參考補充小節(jié)canvas的各種方法么抑进?本章內(nèi)容就是用來講解cavas的各種方法的哦~
大大要點
所有的畫布操作都只影響后續(xù)的繪制弥姻,對之前已經(jīng)繪制過的內(nèi)容沒有影響
所有的畫布操作都只影響后續(xù)的繪制,對之前已經(jīng)繪制過的內(nèi)容沒有影
所有的畫布操作都只影響后續(xù)的繪制掺涛,對之前已經(jīng)繪制過的內(nèi)容沒有影響
切記切記蚁阳,重要事情說三遍!8胝铡!
一颠悬、位移translate方法
首先看下面的代碼
paint.setColor(Color.BLUE);
//位移
canvas.translate(200, 300);
//在坐標原點畫一個藍色的圓形
canvas.drawCircle(0,0,100,paint);
paint.setColor(Color.MAGENTA);
//位移
canvas.translate(200, 300);
//在坐標原點畫一個粉紅色的圓形
canvas.drawCircle(0,0,100,paint);
效果如下:
由此矮燎,我們可以看出來:
位移是基于當前位置移動,而不是每次基于屏幕左上角的(0,0)點移動,初始默認是屏幕左上角赔癌。
可以這樣想诞外,坐標軸控制繪畫的位置,translate的時候灾票,可以想象一個活動的坐標軸在移動峡谊。我們拿著坐標軸的中心點進行位置移動,每一次的移動都以上一次的坐標軸為參考物刊苍。
二既们、縮放scale方法
首先,看一下縮放方法:
//1
public void scale (float sx, float sy);
//2
public final void scale(float sx, float sy, float px, float py) {
translate(px, py);
scale(sx, sy);
translate(-px, -py);
}
參數(shù)含義:
- sx: x軸的縮放比例正什,縮放中心默認坐標軸原點啥纸,縮放前的值*sx的絕對值=縮放后的值;如果sx<0,則再根據(jù)x軸進行翻轉
- sy: y軸的縮放比例婴氮,縮放中心默認坐標軸原點斯棒,縮放前的值*sy的絕對值=縮放后的值;如果sy<0,則根據(jù)y軸進行翻轉
- px,py: 設置縮放中心
首先要注意以下幾點:
- cavas的操作效果是疊加的主经,即影響的該畫布之后的所有組件荣暮!
- translate(px, py)移動的物理距離分別是px和py,經(jīng)過scale(sx, sy)縮放后再通過translate(-px, -py)位移罩驻,移動的物理距離就是-px*sx和-py*sy穗酥。
看著覺得疑惑,不要擔心惠遏,我們下邊跟著代碼會理解的哦O(∩_∩)O~
為了更好地理解迷扇,我們可以參考下邊的demo:
先位移至一定位置,繪制藍色方框爽哎,縮放后蜓席,繪制黑色方框
//位移,繪制藍色课锌,縮放后厨内,繪制黑色方框
canvas.translate(200, 300);
paint.setColor(Color.BLUE);
canvas.drawRect(new RectF(0,0,30,30),paint);
paint.setColor(Color.BLACK);
canvas.scale(-0.5f,-1,100,0);
canvas.drawRect(new RectF(0,0,30,30),paint);
上邊的代碼可以用下邊的代碼代替祈秕,為了方便理解,我們每一個分解步驟雏胃,都繪制一個方框请毛,一步步跟著代碼走。
canvas.translate(200, 300);
paint.setColor(Color.BLUE);
canvas.drawRect(new RectF(0,0,30,30),paint);
canvas.translate(100,0);
paint.setColor(Color.MAGENTA);
canvas.drawRect(new RectF(0,0,30,30),paint);
canvas.scale(0.5f,1);
paint.setColor(Color.YELLOW);
canvas.drawRect(new RectF(0,0,30,30),paint);
canvas.scale(-1,-1);
paint.setColor(Color.GRAY);
canvas.drawRect(new RectF(0,0,30,30),paint);
canvas.translate(-100,0);
paint.setColor(Color.BLACK);
canvas.drawRect(new RectF(0,0,30,30),paint);
效果圖如下
可以看出瞭亮,這兩種代碼的效果是一樣的方仿,
總之,我們可以這樣理解统翩,每一次的操作仙蚜,我們都進行了一次畫布的變動,這次的變動對于前邊的繪制沒有任何影響厂汗,但對后邊的所有操作都有影響委粉。
現(xiàn)在,我們在添加一些新代碼和圖理解一下
canvas.translate(200, 300);
paint.setColor(Color.BLUE);
canvas.drawRect(new RectF(0,0,30,30),paint);
paint.setColor(Color.BLACK);
canvas.scale(-0.5f,-1,100,0);
canvas.drawRect(new RectF(0,0,30,30),paint);
//新代碼
paint.setColor(Color.RED);
canvas.translate(100,100);
canvas.drawRect(new RectF(0,0,30,30),paint);
效果:
三娶桦、旋轉rotate
public void rotate (float degrees);
public final void rotate(float degrees, float px, float py) {
translate(px, py);
rotate(degrees);
translate(-px, -py);
}
- 默認旋轉中心為原點,正值順時針
canvas.translate(300, 300);
canvas.drawCircle(0,0,200,paint);
canvas.drawCircle(0,0,180,paint);
for (int i = 0; i <=360; i=i+10) {
canvas.drawLine(-200,0,-180,0,paint);
canvas.rotate(10);
}
四贾节、錯切skew
public void skew (float sx, float sy)
- float sx:將畫布在x方向上傾斜相應的角度,sx傾斜角度的tan值
- float sy:將畫布在y軸方向上傾斜相應的角度衷畦,sy為傾斜角度的tan值.
canvas.translate(300, 300);
paint.setColor(Color.GREEN);
canvas.drawRect(new RectF(0,0,100,100),paint);
paint.setColor(Color.BLACK);
canvas.skew(0.5f,0.5f);
canvas.drawRect(new RectF(0,0,100,100),paint);
paint.setColor(Color.RED);
canvas.skew(0.5f,0.5f);
canvas.drawRect(new RectF(0,0,100,100),paint);
五栗涂、保存和恢復畫布狀態(tài)
1. 保存save和恢復restore
Save():每次調(diào)用Save()函數(shù),都會把當前的畫布的狀態(tài)進行保存,即保存當前Canvas的狀態(tài)祈争,然后放入特定的棧中戴差,這樣之后,我們就可以調(diào)用Canvas的平移铛嘱、放縮暖释、旋轉、錯切墨吓、裁剪等操作啦球匕;
restore():每當調(diào)用Restore()函數(shù),就會把棧中最頂層的畫布狀態(tài)取出來帖烘,并按照這個狀態(tài)恢復當前的畫布亮曹,在這個畫布上做畫,也可以說秘症,是用來恢復Canvas之前保存的狀態(tài)照卦,防止save后對Canvas執(zhí)行的操作對后續(xù)的繪制有影響。
注意:save和restore要配對使用(restore可以比save少乡摹,但不能多)役耕,如果restore調(diào)用次數(shù)比save多,會引發(fā)Error聪廉。
canvas.drawColor(Color.RED);
//保存的畫布大小為全屏幕大小
canvas.save();
//要在畫圖之前對canvas進行clip瞬痘,如果畫圖之后再對canvas進行clip不會影響到已經(jīng)畫好的圖形故慈。一定要記住clip是針對canvas而非圖形
canvas.clipRect(new Rect(0, 0, 400, 400));
canvas.drawColor(Color.GREEN);
//保存畫布大小為Rect(0, 0, 500, 500)
canvas.save();
canvas.clipRect(new Rect(50, 50, 350, 350));
canvas.drawColor(Color.BLUE);
canvas.save();
canvas.clipRect(new Rect(100, 100, 300, 300));
canvas.drawColor(Color.YELLOW);
canvas.save();
canvas.clipRect(new Rect(150, 150, 250, 250));
canvas.drawColor(Color.MAGENTA);
效果圖:
在上述代碼下邊加上如下代碼
//將棧頂?shù)漠嫴紶顟B(tài)取出來,作為當前畫布框全,并畫成黃色背景
canvas.restore(); //①
canvas.drawColor(Color.WHITE); //②
如果只添加①的話察绷,顯示效果沒有變化的,添加①②的話津辩,則效果如下:
補充:Clip系列函數(shù)如下:
boolean clipPath(Path path)
boolean clipPath(Path path, Region.Op op)
boolean clipRect(Rect rect, Region.Op op)
boolean clipRect(RectF rect, Region.Op op)
boolean clipRect(int left, int top, int right, int bottom)
boolean clipRect(float left, float top, float right, float bottom)
boolean clipRect(RectF rect)
boolean clipRect(float left, float top, float right, float bottom, Region.Op op)
boolean clipRect(Rect rect)
boolean clipRegion(Region region)
boolean clipRegion(Region region, Region.Op op)
后記
每一次的變動拆撼,可以理解為在改變畫布的坐標軸??
參考網(wǎng)址
感謝大家的批評指正~