自定義View的繪制

這是一篇總結性地文章凡纳,內容來自扔物線文章以及網易公開課,本文是自己對文章的總結
一、View的坐標系

每一個子View都有一個自己的坐標系领铐,并且互不影響悯森,坐標系的原點是View的左上角,遵循右正左負绪撵,下正上負

如這張圖所示瓢姻,在左上定點為畫布的原點,圓心的左邊是(300,300)


image.png
二音诈、canvas的作用

1.canvas可以指定繪制的位置幻碱,以及繪制什么樣的圖層

canvas.drawColor() 在整個繪制層上繪制一層背景色

三绎狭、Paint負責繪制的風格

繪制的顏色,抗鋸齒褥傍,繪制線條的方式儡嘶,實心還是空心等等和風格相關的都是由paint來做的

Paint.setAntiAlias(boolean aa) 設置抗鋸齒開關
Paint.setStyle(Paint.Style.STROKE) 畫出圖形的線條 不會填充整個圖形
Paint.setStrokeCap(cap) 設置線條端點形狀
Paint. setShader 設置著色器
Paint.setColorFilter 設置顏色的過濾效果 比如加濾鏡
Paint.setStrokeJoin 設置線條拐角的方式
Paint.setDither(boolean dither) 加入抖動效果有規(guī)律地擾亂圖像來讓圖像對于肉眼更加真實
Paint.setFilterBitmap(filterBitmap)優(yōu)化圖像放大后的效果,消除馬賽克
Paint.setPathEffect 圖像外圍輪廓線的效果
Paint.setShadowLayer 給繪制的內容加一層陰影 BlurMaskFilter 模糊效果

1. Paint.setStrokeCap(cap)效果示意圖

畫筆圓角效果

2. Paint.setFilterBitmap(true)效果示意圖
左邊是未開啟優(yōu)化的恍风,右邊是開啟優(yōu)化的蹦狂,可以看到少了許多馬賽克的效果

設置雙線性過濾

3. Paint.setStrokeJoin效果示意圖

拐角的效果

4.使用著色器可以實現(xiàn)一種規(guī)律性的變化。著色器分為三類 線性漸變new LinearGradient朋贬,從中心進行輻射漸變RadialGradient,像雷達
一樣掃描的漸變SweepGradient凯楔, 使用圖像來圖形上色 BitmapShader,將多個著色器組合起來使用的ComposeShader



線性的著色器示例

image.png

    /**
        * 1.線性渲染,LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], @Nullable float positions[], @NonNull TileMode tile)
        * (x0,y0):漸變起始點坐標
        * (x1,y1):漸變結束點坐標
        * color0:漸變開始點顏色,16進制的顏色表示锦募,必須要帶有透明度
        * color1:漸變結束顏色
        * colors:漸變數(shù)組
        * positions:位置數(shù)組摆屯,position的取值范圍[0,1],作用是指定某個位置的顏色值,如果傳null糠亩,漸變就線性變化虐骑。
        * tile:用于指定控件區(qū)域大于指定的漸變區(qū)域時,空白區(qū)域的顏色填充方法
        */
       mShader = new LinearGradient(0, 0, 500, 500, new int[]{Color.RED, Color.BLUE, Color.GREEN}, new float[]{0.f,0.7f,1}, Shader.TileMode.REPEAT);
       mPaint.setShader(mShader);
       canvas.drawRect(0,0,1000,1000, mPaint);

環(huán)形的著色器示例


image.png
   /* 環(huán)形渲染削解,RadialGradient(float centerX, float centerY, float radius, @ColorInt int colors[], @Nullable float stops[], TileMode tileMode)
        * centerX ,centerY:shader的中心坐標富弦,開始漸變的坐標
        * radius:漸變的半徑
        * centerColor,edgeColor:中心點漸變顏色,邊界的漸變顏色
        * colors:漸變顏色數(shù)組
        * stoops:漸變位置數(shù)組氛驮,類似掃描漸變的positions數(shù)組腕柜,取值[0,1],中心點為0,半徑到達位置為1.0f
        * tileMode:shader未覆蓋以外的填充模式矫废。
        */
       mShader = new RadialGradient(250, 250, 250, new int[]{Color.GREEN, Color.YELLOW, Color.RED}, null, Shader.TileMode.CLAMP);
       mPaint.setShader(mShader);
       canvas.drawCircle(250, 250, 250, mPaint);

位圖的著色器示例


image.png
       /**
        * 位圖渲染盏缤,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
        * Bitmap:構造shader使用的bitmap
        * tileX:X軸方向的TileMode
        * tileY:Y軸方向的TileMode
              REPEAT, 繪制區(qū)域超過渲染區(qū)域的部分,重復排版
              CLAMP蓖扑, 繪制區(qū)域超過渲染區(qū)域的部分唉铜,會以最后一個像素拉伸排版
              MIRROR, 繪制區(qū)域超過渲染區(qū)域的部分,鏡像翻轉排版
        */
       mShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.MIRROR);
       mPaint.setShader(mShader);
       canvas.drawRect(0,0,500, 500, mPaint);

組合的著色器示例

   /**
         * 組合渲染律杠,
         * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, Xfermode mode)
         * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, PorterDuff.Mode mode)
         * shaderA,shaderB:要混合的兩種shader
         * Xfermode mode: 組合兩種shader顏色的模式
         * PorterDuff.Mode mode: 組合兩種shader顏色的模式
         */
        BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        LinearGradient linearGradient = new LinearGradient(0, 0, 1000, 1600, new int[]{Color.RED, Color.GREEN, Color.BLUE}, null, Shader.TileMode.CLAMP);
        mShader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY);
        mPaint.setShader(mShader);
        canvas.drawCircle(250, 250, 250, mPaint);
三潭流、Canvas重點API

drawArc :畫扇形
drawPath(Path,Paint):畫自定義的圖形
drawTextOnPath:沿著一趟線繪制文字

1.對于drawPath需要傳入path對象。path對象又有幾種屬性柜去。

addXXX 表示添加某圖形

quadTo:貝塞爾曲線
moveTo:將圓點移動到指定的位置灰嫉,不管畫什么圖形都是從當前位置開始畫的,通過moveTo可以指定畫筆起始的位置嗓奢。
close() 自動封閉讼撒,假設畫了三角形的兩邊后直接調用該方法,會自動將兩點連接起來形成封閉。
setFillType(Path.FillType ft) 設置填充方式

2.drawText難點

1.drawText指定的x根盒,y是要繪制的文字左下角的坐標钳幅,縱坐標y代表文字的基線


image.png

2.可以使用StaticLayout來實現(xiàn)繪制文字的自動換行


image.png
  1. setTypeface設置字體
  2. setStrikeThruText刪除線setUnderlineText下劃線
  3. setLetterSpacing字符的間距
  4. setFontFeatureSettings使用css的方式設置字體
  5. setTextAlign對其方式
  6. setTextLocale設置繪制文字的地域文字類型。大陸簡體 臺灣繁體
  7. getFontSpacing獲取推薦的行距炎滞,可以在換行繪制時使用
canvas.drawText(texts[1], 100, 150 + paint.getFontSpacing, paint);

4.canvas的裁切
繪制的內容超出這個范圍會被裁切掉敢艰,使用clipRect方法。clipPath

5.保存canvas的一次繪制狀態(tài)
canvas.save厂榛, canvas.restore盖矫。幾何變化一定要配合save和restore來配合使用。否則將后續(xù)繪制也受之前的影響

canvas的幾何變換

canvas的幾何變換代碼執(zhí)行順序是倒序的击奶,如果想要先旋轉再平移辈双,那么平移代碼要寫在最上面,再寫旋轉的代碼柜砾。translate湃望,scale,rotate痰驱,skew

6.canvas的平移
使用translate方法讓中心點平移到某個位置,由于canvas的幾何變換是反著的证芭,所以如果要先平移到一個點,再移動回原點要先寫移動回原點的代碼担映,再寫移動到其他位置的代碼废士。

7.使用matris矩陣來變換
post..方法代表在前面插入,也就是變換代碼是順序執(zhí)行的
per..方法是往后邊的代碼插入蝇完,也就是和canvas的變換順序官硝,會插入到其他變換代碼的后面。

四短蜕、使用Camera來實現(xiàn)三維旋轉

image.png

1.camera.save/restore/applytoCanvas
camera的操作是在圖像的原點(0,0)進行的氢架,因此使用camera變化是不對稱的,如果想要在圖形的中心點進行變化朋魔,需要配合canvas的translate方法將canvas移動到中心點進行變化岖研,然后再移動回去。因為camera是不支持設置軸心的警检,軸心永遠是(0,0點)孙援。

2.使用setLocation來將相機的位置向后移動
相機后移投影的圖像變小。一般情況不需要移動x扇雕,y 只需要移動z軸赃磨。因為相機是在z軸上。
camera.setLocation(0, 0, newZ);

**3.camera的旋轉正方向

image.png

View繪制的過程

1.新繪制的總是會覆蓋之前繪制的內容
2.View的繪制過程是從drawBackground(不能重寫)洼裤,onDraw繪制主題,dispatchDraw繪制子view,drawForeground繪制前景色腮鞍,而這些都是由draw方法觸發(fā)的
3.如果是直接繼承view值骇,super.onDraw并沒有什么用,因為onDraw本身就是空實現(xiàn)
4.ViewGroup在通過onDraw繪制完自身后移国,會通過onDispatchDraw方法繪制子View
5.ViewGroup默認會跳過draw方法而直接執(zhí)行dispatchDraw吱瘩,如果想讓它繪制自身,使用setWillNotDraw(false)來執(zhí)行完整的繪制流程

hencoder的圖片

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末迹缀,一起剝皮案震驚了整個濱河市使碾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祝懂,老刑警劉巖票摇,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異砚蓬,居然都是意外死亡矢门,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門灰蛙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祟剔,“玉大人,你說我怎么就攤上這事摩梧∥镅樱” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵仅父,是天一觀的道長叛薯。 經常有香客問我,道長驾霜,這世上最難降的妖魔是什么案训? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮粪糙,結果婚禮上强霎,老公的妹妹穿的比我還像新娘。我一直安慰自己蓉冈,他們只是感情好城舞,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寞酿,像睡著了一般家夺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伐弹,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天拉馋,我揣著相機與錄音,去河邊找鬼。 笑死煌茴,一個胖子當著我的面吹牛随闺,可吹牛的內容都是我干的。 我是一名探鬼主播蔓腐,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼矩乐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了回论?” 一聲冷哼從身側響起散罕,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎傀蓉,沒想到半個月后欧漱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡僚害,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年硫椰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萨蚕。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡靶草,死狀恐怖,靈堂內的尸體忽然破棺而出岳遥,到底是詐尸還是另有隱情奕翔,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布浩蓉,位于F島的核電站派继,受9級特大地震影響,放射性物質發(fā)生泄漏捻艳。R本人自食惡果不足惜驾窟,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望认轨。 院中可真熱鬧绅络,春花似錦、人聲如沸嘁字。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纪蜒。三九已至衷恭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纯续,已是汗流浹背随珠。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工灭袁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牙丽。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓简卧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親烤芦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內容