久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

8.3.16 Canvas API詳解(Part 1)

 小飛苑 2017-01-04

本節(jié)引言:

前面我們花了13小節(jié)詳細(xì)地講解了Android中Paint類大部分常用的API,,本節(jié)開(kāi)始我們來(lái)講解 Canvas(畫板)的一些常用API,,我們?cè)?/p>

  • 8.3.1 三個(gè)繪圖工具類詳解
  • 中已經(jīng)列出了我們可供調(diào)用的一些方法,我們分下類:

    • drawXxx方法族:以一定的坐標(biāo)值在當(dāng)前畫圖區(qū)域畫圖,,另外圖層會(huì)疊加,, 即后面繪畫的圖層會(huì)覆蓋前面繪畫的圖層。
    • clipXXX方法族:在當(dāng)前的畫圖區(qū)域裁剪(clip)出一個(gè)新的畫圖區(qū)域,,這個(gè) 畫圖區(qū)域就是canvas對(duì)象的當(dāng)前畫圖區(qū)域了,。比如:clipRect(new Rect()), 那么該矩形區(qū)域就是canvas的當(dāng)前畫圖區(qū)域
    • getXxx方法族:獲得與Canvas相關(guān)一些值,比如寬高,,屏幕密度等,。
    • save(),restore(),,saveLayer(),,restoreToCount()等保存恢復(fù)圖層的方法
    • translate(平移),scale(縮放),,rotate(旋轉(zhuǎn)),,skew(傾斜)

    當(dāng)然還有其他一些零散的方法,嗯,,從本節(jié)開(kāi)始我會(huì)挑一些感覺(jué)有點(diǎn)意思的API來(lái)進(jìn)行學(xué)習(xí)~

    而本節(jié)先給大家?guī)?lái)的是translate(平移),,scale(縮放),rotate(旋轉(zhuǎn)),,skew(傾斜) 以及save(),,restore()的詳解!

    官方API文檔:Canvas

    另外我們先要明確Canvas中X軸與Y軸的方向:


    1.translate(平移)

    方法translate(float dx, float dy)

    解析:平移,,將畫布的坐標(biāo)原點(diǎn)向左右方向移動(dòng)x,,向上下方向移動(dòng)y,canvas默認(rèn)位置在(0,0)

    參數(shù):dx為水平方向的移動(dòng)距離,,dy為垂直方向的移動(dòng)距離

    使用示例

    for(int i=0; i < 5; i++) {
        canvas.drawCircle(50, 50, 50, mPaint);
        canvas.translate(100, 100);
    }
    運(yùn)行效果


    2.rotate(旋轉(zhuǎn))

    方法rotate(float degrees) / rotate(float degrees, float px, float py)

    解析:圍繞坐標(biāo)原點(diǎn)旋轉(zhuǎn)degrees度,,值為正順時(shí)針

    參數(shù):degrees為旋轉(zhuǎn)角度,px和py為指定旋轉(zhuǎn)的中心點(diǎn)坐標(biāo)(px,py)

    使用示例

    Rect rect = new Rect(50,0,150,50);
    canvas.translate(200, 200);
    for(int i = 0; i < 36;i++){
        canvas.rotate(10);
        canvas.drawRect(rect, mPaint);
    }

    運(yùn)行效果

    代碼分析

    這里我們先調(diào)用了translate(200,,200)將canvas的坐標(biāo)原點(diǎn)移向了(200,200),,再進(jìn)行繪制,所以我們 繪制的結(jié)果可以完整的在畫布上顯示出來(lái),,假如我們是為rotate設(shè)置了(10,200,200),,會(huì)是這樣一個(gè) 結(jié)果:

    有疑問(wèn)是吧,這個(gè)涉及到Canvas多圖層的概念,,等等會(huì)講~


    3.scale(縮放)

    方法scale(float sx, float sy) / scale(float sx, float sy, float px, float py)

    解析:對(duì)畫布進(jìn)行縮放

    參數(shù):sx為水平方向縮放比例,,sy為豎直方向的縮放比例,px和py我也不知道,,小數(shù)為縮小,, 整數(shù)為放大

    使用示例

    canvas.drawBitmap(bmp,0,0,mPaint);
    canvas.scale(0.8f, 0.8f);
    canvas.drawBitmap(bmp, 0, 0, mPaint);
    canvas.scale(0.8f, 0.8f);
    canvas.drawBitmap(bmp,0,0,mPaint);

    運(yùn)行效果


    4.skew(傾斜)

    方法skew(float sx, float sy)

    解析:傾斜,也可以譯作斜切,,扭曲

    參數(shù):sx為x軸方向上傾斜的對(duì)應(yīng)角度,,sy為y軸方向上傾斜的對(duì)應(yīng)角度,兩個(gè)值都是tan值哦,! 都是tan值,!都是tan值,!比如要在x軸方向上傾斜60度,那么小數(shù)值對(duì)應(yīng):tan 60 = 根號(hào)3 = 1.732,!

    使用示例

    canvas.drawBitmap(bmp,0,0,mPaint);
    canvas.translate(200, 200);
    canvas.skew(0.2f,-0.8f);
    canvas.drawBitmap(bmp,0,0,mPaint);

    運(yùn)行效果


    5.Canvas圖層的概念以及save()和restore()詳解

    我們一般喜歡稱呼Canvas為畫布,童鞋們一直覺(jué)得Canvas就是一張簡(jiǎn)單的畫紙,,那么我想 問(wèn)下多層的動(dòng)畫是怎么用canvas來(lái)完成的,?上面那個(gè)translate平移的例子,為什么 drawCircle(50, 50, 50, mPaint); 參考坐標(biāo)一直是(50,50)那為何會(huì)出現(xiàn)這樣的效果,? 有疑惑的童鞋可能是一直將屏幕的概念與Canvas的概念混淆了,,下面我們來(lái)還原下 調(diào)用translate的案發(fā)現(xiàn)場(chǎng):

    如圖,是畫布坐標(biāo)原點(diǎn)的每次分別在x,,y軸上移動(dòng)100,;那么假如我們要重新回到(0,0) 點(diǎn)處繪制新的圖形呢?怎么破,,translate(-100,-100)的慢慢地平移回去,?不會(huì)真的這么 糾結(jié)吧...

    好吧,不賣關(guān)子了,,我們可以在做平移變換之前將當(dāng)前canvas的狀態(tài)進(jìn)行保存,,其實(shí)Canvas為 我們提供了圖層(Layer)的支持,而這些Layer(圖層)是按"棧結(jié)構(gòu)"來(lái)進(jìn)行管理的

    當(dāng)我們調(diào)用save()方法,,會(huì)保存當(dāng)前Canvas的狀態(tài)然后作為一個(gè)Layer(圖層),,添加到Canvas棧中, 另外,,這個(gè)Layer(圖層)不是一個(gè)具體的類,,就是一個(gè)概念性的東西而已!

    而當(dāng)我們調(diào)用restore()方法的時(shí)候,,會(huì)恢復(fù)之前Canvas的狀態(tài),,而此時(shí)Canvas的圖層棧 會(huì)彈出棧頂?shù)哪莻€(gè)Layer,后繼的Layer來(lái)到棧頂,,此時(shí)的Canvas回復(fù)到此棧頂時(shí)保存的Canvas狀態(tài),!

    簡(jiǎn)單說(shuō)就是:save()往棧壓入一個(gè)Layer,restore()彈出棧頂?shù)囊粋€(gè)Layer,,這個(gè)Layer代表Canvas的 狀態(tài),!也就是說(shuō)可以save()多次,也可以restore()多次,,但是restore的調(diào)用次數(shù)不能大于save 否則會(huì)引發(fā)錯(cuò)誤,!這是網(wǎng)上大部分的說(shuō)法,不過(guò)實(shí)際測(cè)試中并沒(méi)有出現(xiàn)這樣的問(wèn)題,,即使我restore的 次數(shù)多于save,,也沒(méi)有出現(xiàn)錯(cuò)誤~目測(cè)是系統(tǒng)改了,等下測(cè)給大家看~ 來(lái)來(lái)來(lái),寫個(gè)例子驗(yàn)證下save和restore的作用,!

    寫個(gè)例子

    例子代碼

    canvas.save();  //保存當(dāng)前canvas的狀態(tài)
    
    canvas.translate(100, 100);
    canvas.drawCircle(50, 50, 50, mPaint);
    
    canvas.restore();  //恢復(fù)保存的Canvas的狀態(tài)
    canvas.drawCircle(50, 50, 50, mPaint);

    運(yùn)行結(jié)果

    不用說(shuō)什么了吧,,代碼和結(jié)果已經(jīng)說(shuō)明了一切,接著我們搞得復(fù)雜點(diǎn),,來(lái)一發(fā) 多個(gè)save()和restore(),!

    例子代碼:

    canvas.save();
    
    canvas.translate(300, 300);
    canvas.drawBitmap(bmp, 0, 0, mPaint);
    canvas.save();
    
    canvas.rotate(45);
    canvas.drawBitmap(bmp, 0, 0, mPaint);
    canvas.save();
    
    canvas.rotate(45);
    canvas.drawBitmap(bmp, 0, 0, mPaint);
    canvas.save();
    
    canvas.translate(0, 200);
    canvas.drawBitmap(bmp, 0, 0, mPaint);

    運(yùn)行結(jié)果

    結(jié)果分析

    首先平移(300,300)畫圖,然后旋轉(zhuǎn)45度畫圖,,再接著旋轉(zhuǎn)45度畫圖,,接著平移(0,200), 期間每次畫圖前都save()一下,,看到這里你可能有個(gè)疑問(wèn),,最后這個(gè)平移不是y移動(dòng)200 么,怎么變成向左了,?嘿嘿,,我會(huì)告訴你rotate()旋轉(zhuǎn)的是整個(gè)坐標(biāo)軸么?坐標(biāo)軸的 變化:

    嗯,,rotate()弄懂了是吧,,那就行,接著我們來(lái)試試restore咯~我們?cè)谧詈罄L圖的前面 加兩個(gè)restore(),!

    canvas.restore();
    canvas.restore();
    canvas.translate(0, 200);
    canvas.drawBitmap(bmp, 0, 0, mPaint);

    運(yùn)行結(jié)果

    不說(shuō)什么,,自己體會(huì),再加多個(gè)restore(),!

    有點(diǎn)意思,,再來(lái),繼續(xù)加restore()

    嗯,,好像不可以再寫restore了是吧,,因?yàn)槲覀冎籹ave了四次,按照網(wǎng)上的說(shuō)法,, 這會(huì)報(bào)錯(cuò)的,,真的是這樣嗎?這里我們調(diào)用Canvas給我們提供的一個(gè)獲得當(dāng)前棧中 有多少個(gè)Layer的方法:getSaveCount(),;然后在save()和restore()的前后都 加一個(gè)Log將棧中Layer的層數(shù)打印出來(lái):

    結(jié)果真是喜聞樂(lè)見(jiàn),,畢竟實(shí)踐出真知,可能是Canvas改過(guò)吧,,或者其他原因,,這里 要看源碼才知道了,時(shí)間關(guān)系,,這里我們知道下restore的次數(shù)可以比save多就好了,, 但是還是建議restore的次數(shù)還是少于save,,以避免造成不必要的問(wèn)題~ 至于進(jìn)棧和出棧的流程我就不話了,筆者自己動(dòng)筆畫畫,,非常容易理解,!


    6.saveLayer()與restoreToCount()講解

    其實(shí)這兩個(gè)方法和save以及restore大同小異,只是在后者的基礎(chǔ)上多了一些東東而已,, 比如saveLayer(),,有下面多個(gè)重載方法:

    你可以理解為save()方法保存的是整個(gè)Canvas,而saveLayer()則可以選擇性的保存某個(gè)區(qū)域的狀態(tài),, 另外,我們看到餐宿和中有個(gè):int saveFlags,,這個(gè)是設(shè)置改保存那個(gè)對(duì)象的,!可選值有:

    標(biāo)記 說(shuō)明
    ALL_SAVE_FLAG 保存全部的狀態(tài)
    CLIP_SAVE_FLAG 保存裁剪的某個(gè)區(qū)域的狀態(tài)
    CLIP_TO_LAYER_SAVE_FLAG 保存預(yù)先設(shè)置的范圍里的狀態(tài)
    FULL_COLOR_LAYER_SAVE_FLAG 保存彩色涂層
    HAS_ALPHA_LAYER_SAVE_FLAG 不透明圖層保存
    MATRIX_SAVE_FLAG Matrix信息(translate,rotate,,scale,,skew)的狀態(tài)保存

    PS:上述說(shuō)明有點(diǎn)問(wèn)題,筆者英語(yǔ)水平低,,可能說(shuō)錯(cuò),,如果有知道的,請(qǐng)務(wù)必指正提出,,謝謝~

    這里我們寫個(gè)例子來(lái)驗(yàn)證下:我們選用CLIP_TO_LAYER_SAVE_FLAG模式來(lái)寫個(gè)例子

    實(shí)現(xiàn)代碼

    RectF bounds = new RectF(0, 0, 400, 400);
    canvas.saveLayer(bounds, mPaint, Canvas.CLIP_TO_LAYER_SAVE_FLAG);
    canvas.drawColor(getResources().getColor(R.color.moss_tide));
    canvas.drawBitmap(bmp, 200, 200, mPaint);
    canvas.restoreToCount(1);
    canvas.drawBitmap(bmp, 300, 200, mPaint);

    運(yùn)行結(jié)果

    關(guān)于saveLayer()后面用到再詳解研究吧~這里先知道個(gè)大概~

    接著到這個(gè)restoreToCount(int),,這個(gè)更簡(jiǎn)單,直接傳入要恢復(fù)到的Layer層數(shù),, 直接就跳到對(duì)應(yīng)的那一層,,同時(shí)會(huì)將該層上面所有的Layer踢出棧,讓該層 成為棧頂~,!比起你寫多個(gè)restore()方便快捷多了~


    7.本節(jié)代碼示例下載:

    嗯,,代碼是寫著測(cè)試的,要來(lái)也沒(méi)多大意思,,不過(guò)可能讀者還是想要,,就貼下鏈接吧!

    代碼下載CanvasDemo.zip 可能你們要的是這個(gè)圖吧,!哈哈~


    本節(jié)小結(jié):

    本節(jié)是糾結(jié)了幾天才寫出來(lái)的,,因?yàn)楣P者一開(kāi)始對(duì)這個(gè)Canvas圖層的概念也不是很清晰, 今天下午做完事捋了捋思路,,晚上再加加班終于把這篇東西寫出來(lái)了,,相信應(yīng)該能幫助 大家更清楚的理解Canvas,進(jìn)階自定義控件時(shí)也不會(huì)一頭霧水~嘿嘿,,本節(jié)就到這里,, 如果有寫錯(cuò)的地方歡迎提出,,萬(wàn)分感謝~

    參考文獻(xiàn)AndroidのCanvasを使いこなす! – 基本的な描畫

      本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
      轉(zhuǎn)藏 分享 獻(xiàn)花(0

      0條評(píng)論

      發(fā)表

      請(qǐng)遵守用戶 評(píng)論公約

      類似文章 更多