View繪制流程

涉及到的類:ViewRootImpl字旭,PhoneWindow据沈,ActivityThread,View鸠珠,ViewGroup巍耗, DecorView
關(guān)系:view的attachInfo中包含ViewRootImpl,PhoneWindow中包含DecorView
創(chuàng)建時機(jī):
入口:doTraversal方法渐排,其由mChoreographer實(shí)例定期調(diào)用或者view自己設(shè)置重會
performTraversals 方法開始整理view繪制的相關(guān)流程炬太,涉及到:
1.測量,具體的測量規(guī)則是什么驯耻,root的測量是怎么來的
2.為啥會有relayoutWindow亲族,涉及到的window和activity的關(guān)系是什么
3.performLayout入口和相關(guān)規(guī)則
4.performDraw入口和相關(guān)規(guī)則,activity和surface的關(guān)系

root的默認(rèn)寬高是屏幕寬高可缚,默認(rèn)模式為MATCH_PARENT 生成的MeasureSpec為EXACTLY模式的屏幕寬高 =》根據(jù)LayoutParam生成MeasureSpec
MeasureSpec 為 32位int值霎迫,高2位表示模式,其余30位表示具體的值
生成root的MeasureSpec值之后帘靡,開始向子View遞歸測量知给,分為兩種情況:
1.View:默認(rèn)實(shí)現(xiàn)是調(diào)用onMeasure設(shè)置view的寬高(在背景寬高(backgroud)和最小寬高(minHeight||minWidth)中取大值,然后通過上一級的MeasureSpec和當(dāng)前默認(rèn)寬高生成當(dāng)前view的MeasureSpec值,生成的規(guī)則是按照上一級的mode來的涩赢,如果上一級不限制大懈甏巍(MeasureSpec.UNSPECIFIED),則為當(dāng)前View的默認(rèn)寬高筒扒,如果上一級限制大星有啊(MeasureSpec.AT_MOST|| MeasureSpec.EXACTLY),則使用上一級的設(shè)置的寬高(這樣的話花墩,當(dāng)前view在layout文件中設(shè)置的wrap_content本質(zhì)上就和match_parent的效果一樣悬秉,所以自定義View時需要自己處理下view的測量工作)
2.ViewGroup:
生成子類的MeasureSpec值在getChildMeasureSpec(這個方法是系統(tǒng)默認(rèn)實(shí)現(xiàn),用于自定義ViewGroup是的測量观游,系統(tǒng)不調(diào)用搂捧,而是重寫者自己調(diào)用的)方法中,生成邏輯是根據(jù)父View的MeasureSpec+子View的LayoutParam共同生成:MeasureSpec可以理解成 父View告訴子View自己當(dāng)前的空間狀態(tài)懂缕,請子View結(jié)合自己的要求(LayoutParam)來生成自己的空間狀態(tài)


MeasureSpec表.png

onMeasure方法是view空間大小狀態(tài)的入口方法,結(jié)束的標(biāo)志就是其寬高被設(shè)置(setMeasuredDimension是默認(rèn)設(shè)置寬高的方法)

performLayout方法是在測量后調(diào)用的王凑,其通過調(diào)用rootView的layout開始將布局事件向View層分發(fā)搪柑,layout方法的主要目的是根據(jù)父View的可用空間和位置信息,計(jì)算出每個子View的位置和可用空間索烹,為onDraw方法做鋪墊工碾,其結(jié)束的標(biāo)志就是設(shè)置view的left top right bottom的坐標(biāo)。
為了實(shí)現(xiàn)上述目的百姓,框架層設(shè)定了layout和onLayout方法渊额,View的layout方法不能被重寫,其主要負(fù)責(zé)調(diào)用自身的onLayout方法垒拢,其中View的onLayout方法是空實(shí)現(xiàn)旬迹,ViewGroup的onLayout是抽象的,具體的onLayout是有具體的ViewGroup實(shí)現(xiàn)類實(shí)現(xiàn)的求类,比如LinearLayout奔垦,其onLayout就自身計(jì)算了子View的位置信息:
、尸疆、椿猎、
//該方法的四個參數(shù)都由父View傳遞,其描述的是當(dāng)前view在父View的位置信息寿弱,同時也告訴子View犯眠,父View的空用空間信息
void layoutVertical(int left, int top, int right, int bottom) {
final int paddingLeft = mPaddingLeft;//當(dāng)前LinearLayout的左邊留白

int childTop;
int childLeft;

// Where right end of child should go
final int width = right - left;//當(dāng)前LiearLayout自身的寬度
int childRight = width - mPaddingRight;//子View的右邊界

// 算出當(dāng)前LinearLayout可給子View使用的空間
int childSpace = width - paddingLeft - mPaddingRight;
final int count = getVirtualChildCount();
switch (majorGravity) {
   …//省略其他計(jì)算childTop(子View頂部起始點(diǎn))的方式
   default:
       childTop = mPaddingTop;//從這里可以看出,childTop是相對于其父ViewGroup的坐標(biāo)症革,不是所有View共用一個坐標(biāo)
       break;
}

for (int i = 0; i < count; i++) {
    final View child = getVirtualChildAt(i);
    if (child == null) {
        childTop += measureNullChild(i);
    } else if (child.getVisibility() != GONE) {
        final int childWidth = child.getMeasuredWidth();
        final int childHeight = child.getMeasuredHeight();

        final LinearLayout.LayoutParams lp =
                (LinearLayout.LayoutParams) child.getLayoutParams();

        int gravity = lp.gravity;
        if (gravity < 0) {
            gravity = minorGravity;
        }
        final int layoutDirection = getLayoutDirection();
        final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
            case Gravity.CENTER_HORIZONTAL:
                childLeft = paddingLeft + ((childSpace - childWidth) / 2)
                        + lp.leftMargin - lp.rightMargin;
                break;

            case Gravity.RIGHT:
                childLeft = childRight - childWidth - lp.rightMargin;
                break;

            case Gravity.LEFT:
            default:
                childLeft = paddingLeft + lp.leftMargin;
                break;
        }

        if (hasDividerBeforeChildAt(i)) {
            childTop += mDividerHeight;
        }

        childTop += lp.topMargin;//加上子View自身的topMargin筐咧,可以看出 margin屬性的值是不計(jì)算在View的高度或者寬度內(nèi)的,而padding是計(jì)算在內(nèi)的
        setChildFrame(child, childLeft, childTop + getLocationOffset(child),
                childWidth, childHeight);
        childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);

        i += getChildrenSkipCount(child, i);
    }
}

地沮、嗜浮、羡亩、
private void setChildFrame(View child, int left, int top, int width, int height) {
//將View在父布局中的可用位置告訴子View,如果子View自己沒有異議危融,就會設(shè)置自身的位置信息為在父View的可用位置
child.layout(left, top, left + width, top + height);
}
畏铆、、吉殃、

performDraw則負(fù)責(zé)分發(fā)draw事件辞居,其會設(shè)置相關(guān)臟區(qū)域,實(shí)現(xiàn)局部重繪蛋勺,ViewRootImpl類中draw方法會在硬件繪制和軟件繪制中選擇一個進(jìn)行繪制瓦灶,這里只關(guān)注下軟件繪制步驟:
1.繪制自身背景
2.繪制自身內(nèi)容(即調(diào)用自身onDraw方法)
3.繪制子View(是一種遞歸)
4.繪制ViewOverlay覆層
5.繪制裝飾,比如滾動條抱完,actionbar等
6.繪制焦點(diǎn)視圖高亮

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贼陶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子巧娱,更是在濱河造成了極大的恐慌碉怔,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禁添,死亡現(xiàn)場離奇詭異撮胧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)老翘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門芹啥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铺峭,你說我怎么就攤上這事墓怀。” “怎么了逛薇?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵捺疼,是天一觀的道長。 經(jīng)常有香客問我永罚,道長啤呼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任呢袱,我火速辦了婚禮官扣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘羞福。我一直安慰自己惕蹄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卖陵,像睡著了一般遭顶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泪蔫,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天棒旗,我揣著相機(jī)與錄音,去河邊找鬼撩荣。 笑死铣揉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的餐曹。 我是一名探鬼主播逛拱,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼台猴!你這毒婦竟也來了朽合?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤卿吐,失蹤者是張志新(化名)和其女友劉穎旁舰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗡官,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年毯焕,在試婚紗的時候發(fā)現(xiàn)自己被綠了衍腥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡纳猫,死狀恐怖婆咸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芜辕,我是刑警寧澤尚骄,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站侵续,受9級特大地震影響倔丈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜状蜗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一需五、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧轧坎,春花似錦宏邮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽械筛。三九已至,卻和暖如春飒炎,著一層夾襖步出監(jiān)牢的瞬間埋哟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工厌丑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留定欧,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓怒竿,卻偏偏與公主長得像砍鸠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耕驰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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