自定義View-第四步:畫布操作

前言

根據(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: 設置縮放中心

首先要注意以下幾點:

  1. cavas的操作效果是疊加的主经,即影響的該畫布之后的所有組件荣暮!
  2. 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)址

canvas變換與操作

感謝大家的批評指正~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市喘沿,隨后出現(xiàn)的幾起案子闸度,更是在濱河造成了極大的恐慌,老刑警劉巖摹恨,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異娶视,居然都是意外死亡晒哄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門肪获,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寝凌,“玉大人,你說我怎么就攤上這事孝赫〗夏荆” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵青柄,是天一觀的道長伐债。 經(jīng)常有香客問我,道長致开,這世上最難降的妖魔是什么峰锁? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮双戳,結果婚禮上虹蒋,老公的妹妹穿的比我還像新娘。我一直安慰自己飒货,他們只是感情好魄衅,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著塘辅,像睡著了一般晃虫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上扣墩,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天傲茄,我揣著相機與錄音毅访,去河邊找鬼。 笑死盘榨,一個胖子當著我的面吹牛喻粹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播草巡,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼守呜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了山憨?” 一聲冷哼從身側響起查乒,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎郁竟,沒想到半個月后玛迄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡棚亩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年蓖议,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讥蟆。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡勒虾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瘸彤,到底是詐尸還是另有隱情修然,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布质况,位于F島的核電站愕宋,受9級特大地震影響,放射性物質發(fā)生泄漏结榄。R本人自食惡果不足惜掏婶,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望潭陪。 院中可真熱鬧雄妥,春花似錦、人聲如沸依溯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黎炉。三九已至枝秤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慷嗜,已是汗流浹背淀弹。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工丹壕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人薇溃。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓菌赖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親沐序。 傳聞我的和親對象是個殘疾皇子琉用,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容