View的工作流程-layout過程

前言

上一篇我們分析了Viewmeasure過程劳吠,這一篇我們再來看下Viewlayout過程贩幻,layout過程相對比measure過程簡單一些舌涨,Layout的入口還是從ViewRootImplperformLayout()開始的慌盯,performLayout()里面調(diào)用layout(),我們來看下layout()方法

View#layout()

    public void layout(int l, int t, int r, int b) {
        if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
            onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        }

        int oldL = mLeft;
        int oldT = mTop;
        int oldB = mBottom;
        int oldR = mRight;

        boolean changed = isLayoutModeOptical(mParent) ?
                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);

        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
            onLayout(changed, l, t, r, b);

            if (shouldDrawRoundScrollbar()) {
                if(mRoundScrollbarRenderer == null) {
                    mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);
                }
            } else {
                mRoundScrollbarRenderer = null;
            }

            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;

            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnLayoutChangeListeners != null) {
                ArrayList<OnLayoutChangeListener> listenersCopy =
                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
                int numListeners = listenersCopy.size();
                for (int i = 0; i < numListeners; ++i) {
                    listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
                }
            }
        }

        mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
        mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
    }

首先會通過setFrame()方法來設(shè)定View的四個(gè)頂點(diǎn)的位置砰诵,也就是ViewmLeftmTop茵臭、mRigh疫诽、tmBottom這四個(gè)值,即View的四個(gè)頂點(diǎn)一旦確定旦委,那么在父容器中的位置就確定了奇徒,再往下會調(diào)用onLayout()方法,View中的onLayout()是一個(gè)空方法缨硝,ViewGroup中是一個(gè)抽象方法摩钙,具體方法都在實(shí)現(xiàn)類里面,下面我們看下FrameLayoutonLayout()方法

FrameLayout#onLayout()

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        layoutChildren(left, top, right, bottom, false /* no force left gravity */);
    }

    void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
        final int count = getChildCount();

        final int parentLeft = getPaddingLeftWithForeground();
        final int parentRight = right - left - getPaddingRightWithForeground();

        final int parentTop = getPaddingTopWithForeground();
        final int parentBottom = bottom - top - getPaddingBottomWithForeground();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();

                final int width = child.getMeasuredWidth();
                final int height = child.getMeasuredHeight();

                int childLeft;
                int childTop;

                int gravity = lp.gravity;
                if (gravity == -1) {
                    gravity = DEFAULT_CHILD_GRAVITY;
                }

                final int layoutDirection = getLayoutDirection();
                final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
                final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;

                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                    case Gravity.CENTER_HORIZONTAL:
                        childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
                        lp.leftMargin - lp.rightMargin;
                        break;
                    case Gravity.RIGHT:
                        if (!forceLeftGravity) {
                            childLeft = parentRight - width - lp.rightMargin;
                            break;
                        }
                    case Gravity.LEFT:
                    default:
                        childLeft = parentLeft + lp.leftMargin;
                }

                switch (verticalGravity) {
                    case Gravity.TOP:
                        childTop = parentTop + lp.topMargin;
                        break;
                    case Gravity.CENTER_VERTICAL:
                        childTop = parentTop + (parentBottom - parentTop - height) / 2 +
                        lp.topMargin - lp.bottomMargin;
                        break;
                    case Gravity.BOTTOM:
                        childTop = parentBottom - height - lp.bottomMargin;
                        break;
                    default:
                        childTop = parentTop + lp.topMargin;
                }

                child.layout(childLeft, childTop, childLeft + width, childTop + height);
            }
        }
    }

這個(gè)方法里主要是遍歷子View查辩,獲取到測量值和設(shè)置的位置屬性胖笛,在計(jì)算出View的四個(gè)頂點(diǎn),最后子View調(diào)用layout()方法再確定自己的位置宜岛。

總結(jié)

重寫onMeasure() 方法時(shí)长踊,一定要調(diào)用 setMeasuredDimension(), 對于 onLayout 方法而言,一定要對 View調(diào)用layout() 方法萍倡,這樣才能將View放置到合適的位置上去身弊。layout 方法分別有四個(gè)參數(shù),依次是 view 相對于 父view 的左邊距,上邊距阱佛,右邊距帖汞,和下邊距,看下下面圖片

坐標(biāo)示意圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凑术,一起剝皮案震驚了整個(gè)濱河市翩蘸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淮逊,老刑警劉巖催首,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泄鹏,居然都是意外死亡翅帜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進(jìn)店門命满,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涝滴,“玉大人,你說我怎么就攤上這事胶台〖叽” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵诈唬,是天一觀的道長韩脏。 經(jīng)常有香客問我,道長铸磅,這世上最難降的妖魔是什么赡矢? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮阅仔,結(jié)果婚禮上吹散,老公的妹妹穿的比我還像新娘。我一直安慰自己八酒,他們只是感情好空民,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著羞迷,像睡著了一般界轩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衔瓮,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天浊猾,我揣著相機(jī)與錄音,去河邊找鬼热鞍。 笑死葫慎,一個(gè)胖子當(dāng)著我的面吹牛单山,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播幅疼,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昼接!你這毒婦竟也來了爽篷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤慢睡,失蹤者是張志新(化名)和其女友劉穎逐工,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漂辐,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泪喊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了髓涯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袒啼。...
    茶點(diǎn)故事閱讀 39,688評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖纬纪,靈堂內(nèi)的尸體忽然破棺而出蚓再,到底是詐尸還是另有隱情,我是刑警寧澤包各,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布摘仅,位于F島的核電站,受9級特大地震影響问畅,放射性物質(zhì)發(fā)生泄漏娃属。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一护姆、第九天 我趴在偏房一處隱蔽的房頂上張望矾端。 院中可真熱鬧,春花似錦卵皂、人聲如沸须床。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豺旬。三九已至,卻和暖如春柒凉,著一層夾襖步出監(jiān)牢的瞬間族阅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工膝捞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坦刀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像鲤遥,于是被迫代替她去往敵國和親沐寺。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評論 2 353

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