筆記:View的工作原理

View的工作原理


  • ViewRoot 和DecorView

ViewRoot對應(yīng)于ViewRootImpl類叹螟,它是連接DecorView和WindowManager的紐帶待锈,View的三大繪制流程都是通過ViewRoot來完成声登。

在ActivityThread中意蛀,當(dāng)Activity對象被創(chuàng)建完畢后志于,會將DecorView添加到Window中,同時會創(chuàng)建ViewRootImpl,并將ViewRootImpl對象和DecorView對象關(guān)聯(lián)装盯。


Activity中View的繪制流程是從ViewRoot的perfromTraversals()方法開始的坷虑,它經(jīng)過measure layout draw 最終將View繪制出來



  • MeasureSpec 代表32位int值,高2位代表specMode,低30位代表specSize

specMode:測量模式

specSize:在某種測量模式下的規(guī)格大小

  • SpecMode 類型

UNSPECIFIED: 父容器不對View限制验夯,要多大有多大猖吴,這種情況一般用于系統(tǒng)內(nèi)部,表示一種測量狀態(tài)挥转。

EXACTLY: 父容器已經(jīng)檢測出View所需要的精確大小,這個時候View的最終大小就是SpecSize所指定的值共屈,它對應(yīng)于LayoutParams中的Match_parent和具體的值绑谣。

AT_MOST: 父容器指定了一個可視大小,即SpecSize拗引,View的大小不能大于這個值,具體要看不同View的具體實現(xiàn)矾削,對應(yīng)于wrap_content


  • ******父容器和LayoutParams一起決定View的MeasureSpec

系統(tǒng)會將LayoutParams在父容器的約束下轉(zhuǎn)換成對應(yīng)的MeasureSpec壤玫,然后再根據(jù)MeasurSpec來確定View測量后的寬高。


  • 父容器測量子View P181


  • DecorView對MeasureSpec的轉(zhuǎn)換測量有點差別哼凯,其MeasureSpec值由窗口尺寸和其自身的LayoutParams來決定


  • View 的mesure方法會調(diào)用onMeasure方法欲间,所有只需要實現(xiàn)View的onMeasure就可以了。

View的measure方法又會被所在的ViewGroup的measureChild方法調(diào)用断部。measureChild方法會遍歷child猎贴,執(zhí)行child的measure。

  • 在onMeasure中又調(diào)用了setMeasureDimension()方法設(shè)置View寬高的測量值蝴光。

  • 在measure完以后她渴,通過getMeasuredWidth/Height()可獲得測量后的寬/高

  • View的Measure過程和Activity的生命周期過程不同步,

  • 如何在Activity中獲取View的寬/高蔑祟?

  1. Activity/View #onWindowFouceChanged()方法趁耗,表示View已經(jīng)初始化完畢,寬高已經(jīng)準(zhǔn)備好

    但該方法會在Acitivty焦點獲取或失去時都會調(diào)用疆虚,也就是onResume和onPause都會調(diào)用苛败。

  2. view.post(runnable)

    view初始化完畢會執(zhí)行runnable,在run()中view.getMesuredWidth()/height

  3. ViewTreeObserver

    當(dāng)View樹狀態(tài)發(fā)生改變满葛,或者View樹內(nèi)部的View發(fā)生改變,onGlobalLayout方法會被調(diào)用著拭,在這里獲取View的寬高纱扭。

    @Override
    protected void onStart() {
        super.onStart();
        ViewTreeObserver viewTreeObserver = vMarqueeView.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                vMarqueeView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = vMarqueeView.getMeasuredWidth();
                int height = vMarqueeView.getMeasuredHeight();
            }
        });
    }
  1. view.measure(int widthMesureSpec,int heightMesureSpec) p192

MATCH_PARENT:不可用,因為不知道父容器的尺寸

WRAP_CONTENT:

        int widthMesureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
        int heightMesureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
        vMarqueeView.measure(widthMesureSpec, heightMesureSpec);

(1<<30)-1 代表(2^30-1) 即使用最大值去構(gòu)造MeasureSpec(View的尺寸使用30位二進(jìn)制表示)


  • layout過程和mearsure過程一樣儡遮,調(diào)用父元素的layout方法乳蛾,layout方法調(diào)用onLayout方法,onlayout方法又會遍歷子元素鄙币,調(diào)用子元素的layout,子元素layout又會調(diào)用onLayout肃叶,如此循環(huán)

  • View的測量寬高和最終寬高的區(qū)別:

getWidth()和getMesuredWidth()

本質(zhì)上是相等的,只是十嘿,getWidht()值mWitdh形成于onLayout之后因惭,而getMesuredWidth()的值形成于mesured之后

(p196)

注意:如過在onLayout中改變了l,r,t,b中某個值,則會影響到getWidth/getHeight绩衷,而不會影響getMesuredWidth/Height值


  • draw過程有點差別蹦魔,但大致相同

調(diào)用draw方法,draw方法會執(zhí)行如下幾步

1.繪制背景(background.draw(cavans))

2.繪制自己(onDraw)

3.繪制children(dispatchDraw(),dispatchDraw又會循環(huán)child執(zhí)行其draw()方法)

4.繪制裝飾(onDrawScrollBars)


  • View的setWillNotDraw(boolean willNotDraw) 優(yōu)化

如果View不做任何繪制內(nèi)容時咳燕,那么設(shè)置這個標(biāo)志位位true后勿决,系統(tǒng)會進(jìn)行相應(yīng)的優(yōu)化,默認(rèn)情況下招盲,View沒有啟用這個標(biāo)志位低缩,但ViewGroup會啟用

當(dāng)自定義View繼承ViewGroup且本身不具備繪制功能時,可以開啟這個標(biāo)志位曹货,從而便于系統(tǒng)的后續(xù)優(yōu)化咆繁,當(dāng)明確知道繼承ViewGroup的View需要通過onDraw繪制相應(yīng)內(nèi)容時,需要顯示的關(guān)閉這個標(biāo)志位


  • 繪制自定義View須知: p201
  1. 讓View支持wrap_content

直接繼承View或ViewGroup的控件顶籽,如果不在onMeasure中對wrap_content做特殊處理顶别,那么在外界布局中使用wrap_content就無法達(dá)到預(yù)期效果豌骏。

  1. 如果有必要,讓View支持padding

直接繼承View的控件,如果不在draw方法中處理padding,那么padding屬性無法起作用缤剧。另外祭衩,直接繼承ViewGroup的控件要在其onMeasure和onLayout中要考慮padding和子元素margin對其造成的影響所坯,不然將導(dǎo)致padding和子元素的margin失效

  1. 盡量不要在View中使用Handler

View內(nèi)部本身提供了post方法

  1. 如果View中有線程或者動畫晒骇,需及時停止,參考View#onDetachedFromWindow

當(dāng)Activity退出或者當(dāng)前View被remove后镰吆,View的onDetachedFromWindow將會被調(diào)用帘撰,對應(yīng)的方法是onAttachedToWindow(),該方法在onDraw之前任何時候調(diào)用万皿,不確定在onMesure之前還是之后調(diào)用摧找,當(dāng)包含該View的Activity被啟動時調(diào)用核行。

  1. View帶有滑動嵌套時,需要處理好滑動嵌套

  • 再次強調(diào)蹬耘,自定義組件繼承View或ViewGroup的芝雪,padding值需要自己處理,在onDraw中處理padding综苔,而margin值由父類處理惩系,對于wrap_content,默認(rèn)是按照match_parent處理如筛,所以也需要自己處理wrap_content情況堡牡,設(shè)置個最小值。

  • 自定義屬性 p206
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末杨刨,一起剝皮案震驚了整個濱河市晤柄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌妖胀,老刑警劉巖芥颈,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赚抡,居然都是意外死亡浇借,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門怕品,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人巾遭,你說我怎么就攤上這事肉康。” “怎么了灼舍?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵吼和,是天一觀的道長。 經(jīng)常有香客問我骑素,道長炫乓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任献丑,我火速辦了婚禮末捣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘创橄。我一直安慰自己箩做,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布妥畏。 她就那樣靜靜地躺著邦邦,像睡著了一般安吁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上燃辖,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天鬼店,我揣著相機與錄音,去河邊找鬼黔龟。 笑死妇智,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捌锭。 我是一名探鬼主播俘陷,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼观谦!你這毒婦竟也來了拉盾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤豁状,失蹤者是張志新(化名)和其女友劉穎捉偏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泻红,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡夭禽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谊路。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讹躯。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缠劝,靈堂內(nèi)的尸體忽然破棺而出潮梯,到底是詐尸還是另有隱情,我是刑警寧澤惨恭,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布秉馏,位于F島的核電站,受9級特大地震影響脱羡,放射性物質(zhì)發(fā)生泄漏萝究。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一锉罐、第九天 我趴在偏房一處隱蔽的房頂上張望帆竹。 院中可真熱鬧,春花似錦氓鄙、人聲如沸馆揉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽升酣。三九已至舷暮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間噩茄,已是汗流浹背下面。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绩聘,地道東北人沥割。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像凿菩,于是被迫代替她去往敵國和親机杜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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