View的繪制流程

1 繪制流程

View的繪制流程從ViewRootImpl的requestLayout()開始


image.png

image.png

2 measure流程

image.png
  • ViewGroup:每個ViewGroup必須復(fù)寫onMeasure案狠,并且在onMeasure中measureChild服傍,并在measureChild結(jié)束之后,調(diào)用setMeasuredDimension設(shè)置自身的寬高骂铁。
final void measure(int widthMeasureSpec, int heightMeasureSpec){
    onMeasure(widthMeasureSpec,heightMeasureSpec);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    //measureChildren
   省略測量子布局的代碼
    setMeasuredDimension(參數(shù));
}
  • View:每個View也必須復(fù)寫onMeasure吹零,并且在onMeasure中設(shè)置自身寬高绩社。
final void measure(int widthMeasureSpec, int heightMeasureSpec){
    //省略其它代碼
    onMeasure(widthMeasureSpec,heightMeasureSpec);
}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

影響View寬高的因素

image.png

即ViewGroup先根據(jù)每個child的MarginLayoutParams(繼承自ViewGroup.LayoutParams稽穆,包括android:layout_width、android:layout_height以及各方向的margin)九孩,結(jié)合自身的MeasureSpec(32位的int類型名段,包含測量模式與測量大小,其中測量模式分為無約束UNSPECIFIED泣懊、精確值EXACTLY以及最大值A(chǔ)T _MOST三種)和padding伸辟,得到需要傳給各個child的約束條件MeasureSpec,然后child根據(jù)MeasureSpec馍刮,minWidth屬性以及background的最小寬高了信夫,確定出child自身的寬高。

當(dāng)某個View的measure()方法返回時卡啰,它以及它的所有子節(jié)點的getMeasuredWidth()和getMeasuredHeight()方法的值就已經(jīng)設(shè)置好了静稻。

3 layout流程

image.png
    public void layout(int l, int t, int r, int b){
        //省略其它代碼
        setFrame(l, t, r, b);
        onLayout(changed, l, t, r, b);
    }

 protected boolean setFrame(int left, int top, int right, int bottom)

layout方法確定view自身的位置,通過setFrame()設(shè)置四個頂點的坐標(biāo)匈辱。然后調(diào)用onLayout()確定所有子元素的位置振湾。
所以在自定義view中,對于ViewGroup亡脸,需要重寫onLayout()方法押搪,并調(diào)用child.layout()對子元素進行布局。如果是View浅碾,由于沒有子View,無需重寫該方法大州。
注意:view可以重寫layout和onLayout,而ViewGroup的只能重寫onLayout垂谢,其layout是final類型厦画。

4 draw流程

image.png··········

可以看一下,draw事件是如何從上往下傳遞滥朱,逐個繪制的:

image.png

5 多次measure根暑、layout和draw

measure力试、layout和draw的流程有可能反反復(fù)復(fù)多次,見下圖购裙。

image.png
  • ViewGroup導(dǎo)致的重繪

一個父View可能對其子View調(diào)用多次measure()方法懂版。舉個例子:父節(jié)點可能首先會通過一次沒有明確尺寸約束(unspecified dimensions)的測量過程來獲取每個子View想獲得的視圖大小。如果最后得到的數(shù)值過大或者過小躏率,那么父節(jié)點會再次對其子View調(diào)用measure()方法躯畴,并使用實際的計算結(jié)果作為輸入?yún)?shù)(即如果子View不同意首次測量結(jié)果,父View會進行第二次帶約束條件的測量)薇芝。

我們知道蓬抄,頂層View為繼承自FrameLayout的DecorView,看看FrameLayout的measure方法:

// FrameLayout的onMeasure函數(shù)夯到,DecorView的onMeasure會調(diào)用這個函數(shù)嚷缭。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int count = getChildCount();
    .....
    for (int i = 0; i < count; i++) {
        final View child = getChildAt(i);
        if (mMeasureAllChildren || child.getVisibility() != GONE) {
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            ......
        }
    }
    ........
    count = mMatchParentChildren.size();
    if (count > 1) {
        for (int i = 0; i < count; i++) {
            ........
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        }
    }
}

當(dāng)然,不可能每次都執(zhí)行兩次measure耍贾,View的Measure函數(shù)中有相關(guān)機制阅爽,只有在FLAG_FORCE_LAYOUT標(biāo)志位為1或者widthMeasureSpec、heightMeasureSpec和上次的不一樣時才會重新measure荐开。

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
  ......
  // 當(dāng)FLAG_FORCE_LAYOUT位為1時付翁,就是當(dāng)前視圖請求一次布局操作
  //或者當(dāng)前widthSpec和heightSpec不等于上次調(diào)用時傳入的參數(shù)的時候
  //才進行從新繪制。
    if (forceLayout || !matchingSize &&
            (widthMeasureSpec != mOldWidthMeasureSpec ||
                    heightMeasureSpec != mOldHeightMeasureSpec)) {
            ......
            onMeasure(widthMeasureSpec, heightMeasureSpec);
            ......
    }
    ......
}
  • ViewRootImpl導(dǎo)致的重繪
    Activity加載的時候晃听,newSurface是true百侧。
private void performTraversals() {
    ......
    boolean newSurface = false;
    //TODO:決定是否讓newSurface為true,導(dǎo)致后邊是否讓performDraw無法被調(diào)用,而是重新scheduleTraversals
    if (!hadSurface) {
        if (mSurface.isValid()) {
            // If we are creating a new surface, then we need to
            // completely redraw it.  Also, when we get to the
            // point of drawing it we will hold off and schedule
            // a new traversal instead.  This is so we can tell the
            // window manager about all of the windows being displayed
            // before actually drawing them, so it can display then
            // all at once.
            newSurface = true;
                    .....
        }
    }
            ......
    if (!cancelDraw && !newSurface) {
        if (!skipDraw || mReportNextDraw) {
            ......
            performDraw();
        }
    } else {  //newSurface為true能扒,會重新scheduleTraversals
        if (viewVisibility == View.VISIBLE) {
            // Try again
            scheduleTraversals();
        } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
            for (int i = 0; i < mPendingTransitions.size(); ++i) {
                mPendingTransitions.get(i).endChangingAnimations();
            }
            mPendingTransitions.clear();
        }
    }
    ......
}
最后編輯于
?著作權(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
  • 文/潘曉璐 我一進店門晦溪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挣跋,你說我怎么就攤上這事三圆。” “怎么了?”我有些...
    開封第一講書人閱讀 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)容