VIew的繪制流程

Android的UI管理系統(tǒng)層級(jí)關(guān)系

image.png

如上圖所示,這就是Android的UI管理系統(tǒng)的層級(jí)關(guān)系叹俏。當(dāng)一個(gè)應(yīng)用啟動(dòng)的時(shí)候,會(huì)啟動(dòng)一個(gè)主Activity,然后Activity會(huì)創(chuàng)建出一個(gè)窗口系統(tǒng)PhoneWindow(每個(gè)Activity都會(huì)創(chuàng)建形病,是Android系統(tǒng)中最基本的窗口系統(tǒng),也是Activity與View進(jìn)行交互的接口)。每個(gè)PhoneWindowd都有一個(gè)DecorView漠吻,它是每個(gè)Activity的根布局量瓜,即為每個(gè)界面的頂級(jí)View,本質(zhì)上是一個(gè)FramLayout途乃。

View的繪制流程:

View的繪制過程是從ViewRoot的performTraversals方法開始的绍傲,在其內(nèi)部依次調(diào)用View的performMeasure,performLayout,performDraw三個(gè)方法。這三個(gè)方法分別完成頂級(jí)View的measure,layout,draw過程欺劳。其中唧取,performMeasure中會(huì)調(diào)用measure方法,而在measure方法中又會(huì)調(diào)用onMeausre()方法划提,然后在onMeaure方法中會(huì)對(duì)所有的子元素進(jìn)行measure過程枫弟,這時(shí)measure流程就從父容器傳遞到了子元素中,子元素會(huì)繼續(xù)重復(fù)父容器的measure過程鹏往,如此反復(fù)即完成了整個(gè)View樹結(jié)構(gòu)的遍歷淡诗,最終 完成View的測量過程。

同理伊履,performLayout和performDraw方法的傳遞流程和performMeasure類似韩容,但不同的是,performDraw的傳遞是在draw方法中通過dispatchDraw方法來下發(fā)的唐瀑,不過本質(zhì)上原理還是一樣的群凶。

流程圖:

image.png

View繪制三部曲

1. onMeasure()

測量單一 view 大小的入口方法是 View 類的measure方法,在該方法中會(huì)調(diào)用 View 類的onMeasure()方法:

image.png

onMeasure的流程:

image.png

getDefaultSize()的邏輯:


image.png

setMeasuredDimension()的作用: 存儲(chǔ)測量后的大泻謇薄(寬/高)

測量的三種模式:

EXACTLY

精確值模式,即當(dāng)我們?cè)诓季治募袨閂iew指定了具體的大小

例如:android:layout_width="100dp",或者當(dāng)我們將View的大小指定為充滿父布局请梢,即為match_parent時(shí),此時(shí)力穗,該View的測量模式即為EXACTLY模式毅弧。

(View的默認(rèn)測量模式為EXACTLY模式)

AT_MOST

最大值模式,此時(shí)View的尺寸不得大于父控件允許的最大尺寸即可当窗。即對(duì)應(yīng)我們給View的寬或高指定為wrap_content時(shí)够坐。

UPSPECIFIED

不指定測量模式,即父視圖沒有限制其大小崖面,子View可以是任何尺寸元咙。該模式一般用于系統(tǒng)內(nèi)部,平時(shí)的Android開發(fā)基本用不到嘶朱。

需要注意的是蛾坯,在setMeasuredDimension()方法調(diào)用之后,我們才能使用getMeasuredWidth()和getMeasuredHeight()來獲取視圖測量出的寬高疏遏,以此之前調(diào)用這兩個(gè)方法得到的值都會(huì)是0脉课。一般情況下我們都在onLayout方法中調(diào)用兩方法來獲取測量的寬和高救军。

2.View的位置確定——onLayout()

image.png

left: View左邊界距離父容器的左邊界的距離

top: View上邊界距離父容器上邊界的距離

right: View右邊界距離父容器左邊界的距離

bottom: View下邊界距離父容器上邊界的距離

image.png

在layout方法中:

image.png

在layout方法中,首先會(huì)通過setFrame方法對(duì)View的四個(gè)頂點(diǎn)的值進(jìn)行賦值倘零,即mLeft, mRight, mTop, mBottom唱遭。當(dāng)各個(gè)頂點(diǎn)的坐標(biāo)確定以后,View在ViewGroup中的位置也就確定了呈驶。接著就要調(diào)用onLayout方法用來確定子元素的位置了拷泽。而對(duì)于View的onLayout方法,這里要說的是袖瞻,它是一個(gè)空方法司致,至于為什么,估計(jì)大家應(yīng)該也能想的通聋迎,因?yàn)閛nLayouta方法就是為了確定子元素在ViewGroup中的位置脂矫,這個(gè)功能方然要有ViewGroup去實(shí)現(xiàn)了啊。而我們點(diǎn)擊進(jìn)入ViewGroup的onLayout方法霉晕,如下:

image.png

我們可以看到他是一個(gè)抽象方法:

我們就可以通過getWidth和getHeight方法來獲取View的寬和高了庭再。

注意:

getMeasuredWidth和getWidth的區(qū)別

①getMeasuredWidth方法獲得的值是setMeasuredDimension方法設(shè)置的值

它的值在measure方法運(yùn)行后就會(huì)確定

②getWidth方法獲得是layout方法中傳遞的四個(gè)參數(shù)中的mRight-mLeft

它的值是在layout方法運(yùn)行后確定的

如果有時(shí)我們刻意去重寫layout方法,并修改方法中的參數(shù)牺堰,那么就會(huì)造成二者的值不相同拄轻。

③一般情況下在onLayout方法中使用getMeasuredWidth方法

而在除onLayout方法之外的地方用getWidth方法。

3.View的繪制——onDraw()

完成了測量和位置確立伟葫,那就差把View繪制出來以讓我們看到了恨搓。這是就要開始進(jìn)入我們的繪制流程了。在調(diào)用了layout方法后筏养,接著ViewRoot會(huì)創(chuàng)建一個(gè)Canvas對(duì)象奶卓,接著調(diào)用View的draw方法來執(zhí)行具體的繪制流程。

1.第一步: 繪制背景

image.png

這一步先先判斷是否設(shè)置了背景撼玄,然后再進(jìn)行背景的繪制。而這個(gè)背景其實(shí)就是我們?cè)赬ML布局中設(shè)置的backgroud屬性,可以使圖片或者是顏色墩邀。

之后我們可以看到這個(gè)注解:skip step 2 & 5 if possible (common case)

意思就是:如果可能掌猛,跳過第2步和第5步(常見情況)

跳過第二步

2.第三步:繪制內(nèi)容

這時(shí)會(huì)調(diào)用view的onDraw方法,來進(jìn)行具體的繪制眉睹。而View的onDraw方法點(diǎn)進(jìn)去會(huì)發(fā)現(xiàn)其實(shí)是一個(gè)空方法荔茬,它需要具體的子類自己去實(shí)現(xiàn)。到底是畫圓還是畫方那就看具體的View了竹海。

3.第四步:對(duì)所有的子View進(jìn)行繪制(dispatchDraw)

這一步是調(diào)用dispatchDraw方法對(duì)其包含的所有的子View進(jìn)行繪制慕蔚。通過調(diào)用drawChild方法來調(diào)用View的draw方法來繪制子View。而如果是單純的一個(gè)子View來說斋配,其dispatchDraw方法是一個(gè)空方法孔飒。

跳過第五步

4.以上都執(zhí)行完后就會(huì)進(jìn)入到第六步灌闺,也是最后一步,這一步的作用是對(duì)視圖的滾動(dòng)條進(jìn)行繪制坏瞄。那么你可能會(huì)奇怪桂对,當(dāng)前的視圖又不一定是ListView或者ScrollView,為什么要繪制滾動(dòng)條呢鸠匀?其實(shí)不管是Button也好蕉斜,TextView也好,任何一個(gè)視圖都是有滾動(dòng)條的缀棍,只是一般情況下我們都沒有讓它顯示出來而已宅此。

通過以上流程分析,相信大家已經(jīng)知道爬范,View是不會(huì)幫我們繪制內(nèi)容部分的父腕,因此需要每個(gè)視圖根據(jù)想要展示的內(nèi)容來自行繪制。如果你去觀察TextView坦敌、ImageView等類的源碼侣诵,你會(huì)發(fā)現(xiàn)它們都有重寫onDraw()這個(gè)方法,并且在里面執(zhí)行了相當(dāng)不少的繪制邏輯狱窘。繪制的方式主要是借助Canvas這個(gè)類杜顺,它會(huì)作為參數(shù)傳入到onDraw()方法中,供給每個(gè)視圖使用蘸炸。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末躬络,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子搭儒,更是在濱河造成了極大的恐慌穷当,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淹禾,死亡現(xiàn)場離奇詭異馁菜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)铃岔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門汪疮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人毁习,你說我怎么就攤上這事智嚷。” “怎么了纺且?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵盏道,是天一觀的道長。 經(jīng)常有香客問我载碌,道長猜嘱,這世上最難降的妖魔是什么衅枫? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮泉坐,結(jié)果婚禮上为鳄,老公的妹妹穿的比我還像新娘。我一直安慰自己腕让,他們只是感情好孤钦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纯丸,像睡著了一般偏形。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上觉鼻,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天俊扭,我揣著相機(jī)與錄音,去河邊找鬼坠陈。 笑死萨惑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仇矾。 我是一名探鬼主播庸蔼,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼贮匕!你這毒婦竟也來了姐仅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤刻盐,失蹤者是張志新(化名)和其女友劉穎掏膏,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敦锌,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馒疹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乙墙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片行冰。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖伶丐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疯特,我是刑警寧澤哗魂,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站漓雅,受9級(jí)特大地震影響录别,放射性物質(zhì)發(fā)生泄漏朽色。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一组题、第九天 我趴在偏房一處隱蔽的房頂上張望葫男。 院中可真熱鬧,春花似錦崔列、人聲如沸梢褐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盈咳。三九已至,卻和暖如春边翼,著一層夾襖步出監(jiān)牢的瞬間鱼响,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工组底, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丈积,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓债鸡,卻偏偏與公主長得像江滨,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娘锁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355