View繪制流程

1、ViewRoot和DecorView

ViewRoot對(duì)應(yīng)于ViewRootImpl(其本質(zhì)不是view而是Handler), 它是連接WindowManager和DecorView的紐帶. View的三大流程都是通過(guò)ViewRoot來(lái)完成的. 當(dāng)一個(gè)Activity對(duì)象在ActivityThread被創(chuàng)建后. 會(huì)將DecorView添加到Window中, 同時(shí)會(huì)創(chuàng)建ViewRootImp對(duì)象, 并將ViewRootImpl對(duì)象和DecorView建立關(guān)聯(lián).

View繪制流程是從ViewRoot的PerformTraversals()開(kāi)始的. 經(jīng)過(guò)三大流程才能將一個(gè)View繪制出來(lái).

關(guān)于PerformTraversals()執(zhí)行之前的操作可以參考View的onAttachedToWindow和onDetachedFromWindow的調(diào)用時(shí)機(jī)分析。其中包含了View的onAttachedToWindow和onDetachedFromWindow的調(diào)用過(guò)程。


dispatchAttachedToWindow

view的onAttachedToWindow調(diào)用發(fā)生在PerformTraversals的1668行,是早于measure發(fā)生的。所以在view的onAttachedToWindow中獲取寬和搞都是不行的。


dispatchOnGlobalLayout

為什么在addOnGlobalLayoutListener接口中可以得到控件的寬和高?因?yàn)樗恼{(diào)用發(fā)生在 PerformTraversals的2250行,晚于measure發(fā)生的。


2、measure過(guò)程

measure調(diào)用發(fā)生在PerformTraversals的2167行。

通過(guò)源碼可以發(fā)現(xiàn)view中的measure為final,即子類(lèi)不能重寫(xiě),measure()方法中調(diào)用了onMeasure(),所以可以重寫(xiě)onMeasure()方法來(lái)達(dá)到measure的目的。

view的onMeasure:一般來(lái)說(shuō)可以不用重寫(xiě),因?yàn)関iew已經(jīng)實(shí)現(xiàn)了改方法。

protected void onMeasure(intwidthMeasureSpec, intheightMeasureSpec) {

?setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),

getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec));

}

ViewGroup的measure:基本上需要重寫(xiě),因?yàn)槿萜鞑季滞枰{(diào)用measureChildren()來(lái)確定子控件的尺寸。舉個(gè)例子LinearLayout

@Override

protected void onMeasure(intwidthMeasureSpec, intheightMeasureSpec) {

?if(mOrientation==VERTICAL) { ? ? ?

? ? ? ? ?measureVertical(widthMeasureSpec,heightMeasureSpec);

? ? }else{

? ? ? ? ?measureHorizontal(widthMeasureSpec,heightMeasureSpec);

}

}

并且LinearLayout的onMeasure()并沒(méi)有調(diào)用super.onMeasure(),說(shuō)明一般容器布局需要完全自己實(shí)現(xiàn)測(cè)量過(guò)程。即先循環(huán)測(cè)量子控件的大小,然后根據(jù)子控件的尺寸以及自身的屬性(一般是子控件寬和高以及margin加上自身的padding)最后通過(guò)調(diào)用setMeasuredDimension()方法來(lái)確定自身的大小。

3、layout過(guò)程


通過(guò)view的源碼可以發(fā)現(xiàn)layout是public的非final并已經(jīng)實(shí)現(xiàn)了改方法。但是ViewGroup中的layout確實(shí)是public和final的。layout方法是確定自身位置的,而onLayout確是用來(lái)確定子控件的位置的(viewgroup中的onLayout通過(guò)遍歷調(diào)用layout方法),所以對(duì)于子控件我們最終可以通過(guò)重寫(xiě)layout方法來(lái)干預(yù)自身的布局,而對(duì)于viewGroup只能通過(guò)父控件來(lái)實(shí)現(xiàn)其位置。其他的過(guò)程基本上和measure相似。

4、draw過(guò)程


draw過(guò)程一般比較簡(jiǎn)單,通過(guò)以下四個(gè)步驟實(shí)現(xiàn):

1、繪制背景background.draw(canvas)

2、繪制自己onDraw()

3、繪制childrendispatchDraw()

4、繪制裝飾onDrawScrollBars()

View繪制過(guò)程傳遞是通過(guò)dispatchDraw()實(shí)現(xiàn)的. 傳遞了自己的畫(huà)布. 這個(gè)方法會(huì)遍歷子元素并且調(diào)用元素的draw()

View一個(gè)特有的方法setWillNotDraw(), 這個(gè)方法是設(shè)置了true那么系統(tǒng)會(huì)進(jìn)行相應(yīng)的優(yōu)化. 在View中默認(rèn)是關(guān)閉的. 而ViewGroup默認(rèn)是開(kāi)啟的. 如果我們繼承了自定義ViewGroup如果還需要繪制自己的內(nèi)容那么需要顯示的關(guān)閉此標(biāo)記.

5、自定義view

1.繼承View重寫(xiě)onDraw方法

這種方法主要用于實(shí)現(xiàn)一些不規(guī)則的效果, 不方便組合布局實(shí)現(xiàn),或者又有動(dòng)態(tài)顯示的一些圖形. 需要自己繪制那么就重寫(xiě)onDraw()方法.這種方法需要自己支持wrap_content和padding

2.繼承ViewGroup派生特殊Layout

這種方式用于實(shí)現(xiàn)自定義布局, 這種布局的實(shí)現(xiàn)稍微復(fù)雜,需要合適的處理ViewGroup的測(cè)量,布局這兩個(gè)過(guò)程,并同時(shí)處理子元素的測(cè)量和布局過(guò)程.

3.繼承特定的View(TextView)

比較常見(jiàn), 一般用于擴(kuò)展已有的View的功能. 這種不需要自己處理wrap_content和padding

4.繼承特定ViewGroup(LinearLayout)

當(dāng)某種效果看起來(lái)像幾種View的組合在一起的時(shí)候,可以采用這種方式. 這種方式不需要自己處理ViewGroup的測(cè)量和布局. 其實(shí)這種方式和2沒(méi)什么區(qū)別, 主要是2更接近于底層的View實(shí)現(xiàn).

自定義View的須知

1、讓View支持wrap_content

2、最好讓你的View支持padding-> 如果直接繼承View,在draw()中不處理padding,那么屬性是無(wú)法起作用的. 還有繼承ViewGroup的控件需要在onMeasure和onLayout中考慮padding和子元素的margin會(huì)造成的影響.

3、盡量不要在View中使用Handler-> 內(nèi)部已經(jīng)提供了post系列方法. 除非很明確要是用Handler發(fā)送消息.

4、View中如果有線程或者動(dòng)畫(huà),需要及時(shí)的停止.-> 當(dāng)包含此View的Activity退出或者此View被remove的時(shí)候,View的onDetachedFromWindow()會(huì)被調(diào)用,可以適當(dāng)處理防止內(nèi)存泄漏.

5、View帶有的滑動(dòng)嵌套時(shí),需要處理好滑動(dòng)沖突.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,577評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,486評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,852評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,600評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,944評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,108評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,652評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,385評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,616評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,798評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,205評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,537評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,334評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,570評(píng)論 2 379

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