ToolBar的gravity屬性設(shè)置為bottom時(shí)的源碼分析

什么叫"專業(yè)性"痒钝,如果以我現(xiàn)在的經(jīng)驗(yàn)來解釋是:一個(gè)人在處理某個(gè)問題時(shí),不依靠他人鸯隅,自己獨(dú)自解決問題的能力澜建。在當(dāng)前這個(gè)社會(huì)中,專業(yè)性是社會(huì)進(jìn)步的基石滋迈,看看身邊的事物霎奢,都是由專業(yè)的人做的,各行各業(yè)各司其職饼灿,推動(dòng)著人類文明的進(jìn)步幕侠;對(duì)于個(gè)人來說,專業(yè)性是指?jìng)€(gè)人在某個(gè)行業(yè)中的精湛程度碍彭,精湛程度越高晤硕,擁有的社會(huì)地位越高。

前幾天在公司做項(xiàng)目時(shí)庇忌,遇到一個(gè)問題:

當(dāng)ToolBar的gravity設(shè)置為bottom時(shí)舞箍,子類的下面顯示不全,如圖皆疹,子類是一個(gè)藍(lán)色背景的TextView

顯示不全.jpg

1. 問題分析

1.1 ToolBar是V7包里面的疏橄,路徑為android.support.v7.widget.Toolbar

1.2 ToolBar繼承的是ViewGroup

1.3 gravity是ToolBar的一個(gè)自定義的屬性

1.4 ToolBar子類的布局?jǐn)[放是在ToolBar.onLayout中操作子類的layout方法來確定位置的

1.5 當(dāng)子類設(shè)置layout_marginBottom屬性時(shí),可完整顯示該子類

2. ToolBar源碼分析

當(dāng)設(shè)置gravity為bottom時(shí),在ToolBar的構(gòu)造函數(shù)中獲得該屬性

android:gravity="bottom"

this.mGravity = a.getInteger(styleable.Toolbar_android_gravity, this.mGravity);//mGravity = 80

直接看onLayout方法:

    boolean isRtl = ViewCompat.getLayoutDirection(this) == 1;
    int width = this.getWidth();
    int height = this.getHeight();
    int paddingLeft = this.getPaddingLeft();
    int paddingRight = this.getPaddingRight();
    int paddingTop = this.getPaddingTop();
    int paddingBottom = this.getPaddingBottom();
    int left = paddingLeft;
    int right = width - paddingRight;
    int[] collapsingMargins = this.mTempMargins;
    collapsingMargins[0] = collapsingMargins[1] = 0;
    int minHeight = ViewCompat.getMinimumHeight(this);
    int alignmentHeight = minHeight >= 0 ? Math.min(minHeight, b - t) : 0;
    if (this.shouldLayout(this.mNavButtonView)) {
        if (isRtl) {
            right = this.layoutChildRight(this.mNavButtonView, right, collapsingMargins, alignmentHeight);
        } else {
            left = this.layoutChildLeft(this.mNavButtonView, paddingLeft, collapsingMargins, alignmentHeight);
        }
    }

    if (this.shouldLayout(this.mCollapseButtonView)) {
        if (isRtl) {
            right = this.layoutChildRight(this.mCollapseButtonView, right, collapsingMargins, alignmentHeight);
        } else {
            left = this.layoutChildLeft(this.mCollapseButtonView, left, collapsingMargins, alignmentHeight);
        }
    }

    if (this.shouldLayout(this.mMenuView)) {
        if (isRtl) {
            left = this.layoutChildLeft(this.mMenuView, left, collapsingMargins, alignmentHeight);
        } else {
            right = this.layoutChildRight(this.mMenuView, right, collapsingMargins, alignmentHeight);
        }
    }

    int contentInsetLeft = this.getCurrentContentInsetLeft();
    int contentInsetRight = this.getCurrentContentInsetRight();
    collapsingMargins[0] = Math.max(0, contentInsetLeft - left);
    collapsingMargins[1] = Math.max(0, contentInsetRight - (width - paddingRight - right));
    left = Math.max(left, contentInsetLeft);
    right = Math.min(right, width - paddingRight - contentInsetRight);
    if (this.shouldLayout(this.mExpandedActionView)) {
        if (isRtl) {
            right = this.layoutChildRight(this.mExpandedActionView, right, collapsingMargins, alignmentHeight);
        } else {
            left = this.layoutChildLeft(this.mExpandedActionView, left, collapsingMargins, alignmentHeight);
        }
    }

    if (this.shouldLayout(this.mLogoView)) {
        if (isRtl) {
            right = this.layoutChildRight(this.mLogoView, right, collapsingMargins, alignmentHeight);
        } else {
            left = this.layoutChildLeft(this.mLogoView, left, collapsingMargins, alignmentHeight);
        }
    }

    boolean layoutTitle = this.shouldLayout(this.mTitleTextView);
    boolean layoutSubtitle = this.shouldLayout(this.mSubtitleTextView);
    int titleHeight = 0;
    Toolbar.LayoutParams lp;
    if (layoutTitle) {
        lp = (Toolbar.LayoutParams)this.mTitleTextView.getLayoutParams();
        titleHeight += lp.topMargin + this.mTitleTextView.getMeasuredHeight() + lp.bottomMargin;
    }

    if (layoutSubtitle) {
        lp = (Toolbar.LayoutParams)this.mSubtitleTextView.getLayoutParams();
        titleHeight += lp.topMargin + this.mSubtitleTextView.getMeasuredHeight() + lp.bottomMargin;
    }

    int centerRight;
    int centerViewsCount;
    int i;
    int titleTop;
    if (layoutTitle || layoutSubtitle) {
        View topChild = layoutTitle ? this.mTitleTextView : this.mSubtitleTextView;
        View bottomChild = layoutSubtitle ? this.mSubtitleTextView : this.mTitleTextView;
        Toolbar.LayoutParams toplp = (Toolbar.LayoutParams)topChild.getLayoutParams();
        Toolbar.LayoutParams bottomlp = (Toolbar.LayoutParams)bottomChild.getLayoutParams();
        boolean titleHasWidth = layoutTitle && this.mTitleTextView.getMeasuredWidth() > 0 || layoutSubtitle && this.mSubtitleTextView.getMeasuredWidth() > 0;
        switch(this.mGravity & 112) {
        case 16:
        default:
            centerRight = height - paddingTop - paddingBottom;
            centerViewsCount = (centerRight - titleHeight) / 2;
            if (centerViewsCount < toplp.topMargin + this.mTitleMarginTop) {
                centerViewsCount = toplp.topMargin + this.mTitleMarginTop;
            } else {
                i = height - paddingBottom - titleHeight - centerViewsCount - paddingTop;
                if (i < toplp.bottomMargin + this.mTitleMarginBottom) {
                    centerViewsCount = Math.max(0, centerViewsCount - (bottomlp.bottomMargin + this.mTitleMarginBottom - i));
                }
            }

            titleTop = paddingTop + centerViewsCount;
            break;
        case 48:
            titleTop = this.getPaddingTop() + toplp.topMargin + this.mTitleMarginTop;
            break;
        case 80:
            titleTop = height - paddingBottom - bottomlp.bottomMargin - this.mTitleMarginBottom - titleHeight;
        }

        int var10000;
        Toolbar.LayoutParams lp;
        int subtitleLeft;
        int subtitleBottom;
        if (isRtl) {
            centerRight = (titleHasWidth ? this.mTitleMarginStart : 0) - collapsingMargins[1];
            right -= Math.max(0, centerRight);
            collapsingMargins[1] = Math.max(0, -centerRight);
            centerViewsCount = right;
            i = right;
            if (layoutTitle) {
                lp = (Toolbar.LayoutParams)this.mTitleTextView.getLayoutParams();
                subtitleLeft = right - this.mTitleTextView.getMeasuredWidth();
                subtitleBottom = titleTop + this.mTitleTextView.getMeasuredHeight();
                this.mTitleTextView.layout(subtitleLeft, titleTop, right, subtitleBottom);
                centerViewsCount = subtitleLeft - this.mTitleMarginEnd;
                titleTop = subtitleBottom + lp.bottomMargin;
            }

            if (layoutSubtitle) {
                lp = (Toolbar.LayoutParams)this.mSubtitleTextView.getLayoutParams();
                titleTop += lp.topMargin;
                subtitleLeft = right - this.mSubtitleTextView.getMeasuredWidth();
                subtitleBottom = titleTop + this.mSubtitleTextView.getMeasuredHeight();
                this.mSubtitleTextView.layout(subtitleLeft, titleTop, right, subtitleBottom);
                i = right - this.mTitleMarginEnd;
                var10000 = subtitleBottom + lp.bottomMargin;
            }

            if (titleHasWidth) {
                right = Math.min(centerViewsCount, i);
            }
        } else {
            centerRight = (titleHasWidth ? this.mTitleMarginStart : 0) - collapsingMargins[0];
            left += Math.max(0, centerRight);
            collapsingMargins[0] = Math.max(0, -centerRight);
            centerViewsCount = left;
            i = left;
            if (layoutTitle) {
                lp = (Toolbar.LayoutParams)this.mTitleTextView.getLayoutParams();
                subtitleLeft = left + this.mTitleTextView.getMeasuredWidth();
                subtitleBottom = titleTop + this.mTitleTextView.getMeasuredHeight();
                this.mTitleTextView.layout(left, titleTop, subtitleLeft, subtitleBottom);
                centerViewsCount = subtitleLeft + this.mTitleMarginEnd;
                titleTop = subtitleBottom + lp.bottomMargin;
            }

            if (layoutSubtitle) {
                lp = (Toolbar.LayoutParams)this.mSubtitleTextView.getLayoutParams();
                titleTop += lp.topMargin;
                subtitleLeft = left + this.mSubtitleTextView.getMeasuredWidth();
                subtitleBottom = titleTop + this.mSubtitleTextView.getMeasuredHeight();
                this.mSubtitleTextView.layout(left, titleTop, subtitleLeft, subtitleBottom);
                i = subtitleLeft + this.mTitleMarginEnd;
                var10000 = subtitleBottom + lp.bottomMargin;
            }

            if (titleHasWidth) {
                left = Math.max(centerViewsCount, i);
            }
        }
    }

    this.addCustomViewsWithGravity(this.mTempViews, 3);
    titleTop = this.mTempViews.size();

    int rightViewsCount;
    for(rightViewsCount = 0; rightViewsCount < titleTop; ++rightViewsCount) {
        left = this.layoutChildLeft((View)this.mTempViews.get(rightViewsCount), left, collapsingMargins, alignmentHeight);
    }

    this.addCustomViewsWithGravity(this.mTempViews, 5);
    rightViewsCount = this.mTempViews.size();

    int centerViewsWidth;
    for(centerViewsWidth = 0; centerViewsWidth < rightViewsCount; ++centerViewsWidth) {
        right = this.layoutChildRight((View)this.mTempViews.get(centerViewsWidth), right, collapsingMargins, alignmentHeight);
    }

    this.addCustomViewsWithGravity(this.mTempViews, 1);
    centerViewsWidth = this.getViewListMeasuredWidth(this.mTempViews, collapsingMargins);
    int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
    int halfCenterViewsWidth = centerViewsWidth / 2;
    int centerLeft = parentCenter - halfCenterViewsWidth;
    centerRight = centerLeft + centerViewsWidth;
    if (centerLeft < left) {
        centerLeft = left;
    } else if (centerRight > right) {
        centerLeft -= centerRight - right;
    }

    centerViewsCount = this.mTempViews.size();

    for(i = 0; i < centerViewsCount; ++i) {
        centerLeft = this.layoutChildLeft((View)this.mTempViews.get(i), centerLeft, collapsingMargins, alignmentHeight);
    }

    this.mTempViews.clear();

1~13行是一些基本操作捎迫;

14~58行由于沒有設(shè)置這些子View晃酒,跳過;

直至198行窄绒,都只是做一些基本操作贝次,mTempViews放進(jìn)了ToolBar子類的集合

在200行遍歷,點(diǎn)進(jìn)layoutChildLeft()方法

    Toolbar.LayoutParams lp = (Toolbar.LayoutParams)child.getLayoutParams();
    int l = lp.leftMargin - collapsingMargins[0];
    left += Math.max(0, l);
    collapsingMargins[0] = Math.max(0, -l);
    int top = this.getChildTop(child, alignmentHeight);
    int childWidth = child.getMeasuredWidth();
    child.layout(left, top, left + childWidth, top + child.getMeasuredHeight());
    left += childWidth + lp.rightMargin;
    return left;

在第7行看到了子View設(shè)置的布局彰导,我只看child.layout()方法的第二個(gè)和第四個(gè)參數(shù)蛔翅,top的值是getChildTop方法得到的,點(diǎn)進(jìn)去

    Toolbar.LayoutParams lp = (Toolbar.LayoutParams)child.getLayoutParams();
    int childHeight = child.getMeasuredHeight();
    int alignmentOffset = alignmentHeight > 0 ? (childHeight - alignmentHeight) / 2 : 0;
    switch(this.getChildVerticalGravity(lp.gravity)) {
    case 16:
    default:
        int paddingTop = this.getPaddingTop();
        int paddingBottom = this.getPaddingBottom();
        int height = this.getHeight();
        int space = height - paddingTop - paddingBottom;
        int spaceAbove = (space - childHeight) / 2;
        if (spaceAbove < lp.topMargin) {
            spaceAbove = lp.topMargin;
        } else {
            int spaceBelow = height - paddingBottom - childHeight - spaceAbove - paddingTop;
            if (spaceBelow < lp.bottomMargin) {
                spaceAbove = Math.max(0, spaceAbove - (lp.bottomMargin - spaceBelow));
            }
        }

        return paddingTop + spaceAbove;
    case 48:
        return this.getPaddingTop() - alignmentOffset;
    case 80:
        return this.getHeight() - this.getPaddingBottom() - childHeight - lp.bottomMargin - alignmentOffset;
    }

第4行的lp.gravity = 0位谋,調(diào)用了getChildVerticalGravity方法山析,點(diǎn)進(jìn)去

private int getChildVerticalGravity(int gravity) {
    int vgrav = gravity & 112;
    switch(vgrav) {
    case 16:
    case 48:
    case 80:
        return vgrav;
    default:
        return this.mGravity & 112;
    }
}

走的是default,mGravity = 80倔幼,返回的是80盖腿,在getChildTop方法會(huì)走 case 80

int alignmentOffset = alignmentHeight > 0 ? (childHeight - alignmentHeight) / 2 : 0;
return this.getHeight() - this.getPaddingBottom() - childHeight - lp.bottomMargin - alignmentOffset;

分析這兩行代碼,padding暫不考慮损同,翻譯下:child.top = ToolBar的高度 - 0 - childHeight - 0 - alignmentOffset 翩腐,alignmentHeight,原來就是onLayout中

int alignmentHeight = minHeight >= 0 ? Math.min(minHeight, b - t) : 0;

alignmentHeight的值為minHeight和ToolBar的高度取最小值膏燃,alignmentOffset的值為:如果alignmentHeight大于0茂卦,則為child的高度減去alignmentHeight在除以2

top 移動(dòng)了 -alignmentOffset 的高度

bottom = top + child.getMeasuredHeight(),跟著移動(dòng)了 -alignmentOffset 的高度

3. 總結(jié)

原來當(dāng)ToolBar設(shè)置

android:gravity="bottom"

時(shí)组哩,子View上下移動(dòng)了alignmentOffset的距離等龙,當(dāng)子View的高度比alignmentHeight小時(shí),alignmentOffset為負(fù)伶贰,子View顯示下移蛛砰,而當(dāng)子View的高度比alignmentHeight大時(shí),alignmentOffset為正黍衙,子View顯示上移動(dòng)泥畅,經(jīng)檢驗(yàn),也確實(shí)是這樣

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末琅翻,一起剝皮案震驚了整個(gè)濱河市位仁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌方椎,老刑警劉巖聂抢,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異棠众,居然都是意外死亡琳疏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來空盼,“玉大人疮薇,你說我怎么就攤上這事∥易ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵迟隅,是天一觀的道長但骨。 經(jīng)常有香客問我,道長智袭,這世上最難降的妖魔是什么奔缠? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮吼野,結(jié)果婚禮上校哎,老公的妹妹穿的比我還像新娘。我一直安慰自己瞳步,他們只是感情好闷哆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著单起,像睡著了一般抱怔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嘀倒,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天屈留,我揣著相機(jī)與錄音,去河邊找鬼测蘑。 笑死灌危,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碳胳。 我是一名探鬼主播勇蝙,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼固逗!你這毒婦竟也來了浅蚪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤烫罩,失蹤者是張志新(化名)和其女友劉穎惜傲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贝攒,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盗誊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哈踱。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荒适,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出开镣,到底是詐尸還是另有隱情刀诬,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布邪财,位于F島的核電站陕壹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏树埠。R本人自食惡果不足惜糠馆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怎憋。 院中可真熱鬧又碌,春花似錦、人聲如沸绊袋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽癌别。三九已至期揪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間规个,已是汗流浹背凤薛。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诞仓,地道東北人缤苫。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像墅拭,于是被迫代替她去往敵國和親活玲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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