文字后面緊跟標(biāo)簽SpareLayout

來(lái)一波需求

有這樣一種需求冒冬,前面一個(gè)View伴逸,后面要帶著幾個(gè)標(biāo)簽缠沈,如果前面的View不太大,那么標(biāo)簽緊跟標(biāo)簽向前移動(dòng)(后三個(gè)條目)错蝴,如果前面的View就很大洲愤,余下來(lái)足夠的空間放標(biāo)簽(第一個(gè)條目)


?酷我音樂(lè)的標(biāo)簽.png

有一個(gè)想法

自己定義一個(gè)ViewGroup,類似于水平布局的LinearLayout顷锰,優(yōu)先測(cè)量后面的View柬赐,最后將剩余的空間給第一個(gè)View,在layout的時(shí)候從左向右擺放官紫,最終實(shí)現(xiàn)效果肛宋,給新的ViewGroup起名叫SpareLayout

  • 測(cè)量的時(shí)候從最后一個(gè)子View開(kāi)始測(cè)量
  • 累加后面所有View的寬度,將剩余空間給第一個(gè)View
  • 高度使用最大高度的View
  • layout時(shí)從左向右擺放測(cè)量好的View

做一點(diǎn)實(shí)現(xiàn)

按上面的思路重寫onMeasure和onLayout方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    //余下的空間
    int spareWidth = 0;
    //最大高度
    int maxHeight = 0;
    //子view從后向前測(cè)量
    for (int i = getChildCount() - 1; i > 0; i--) {
        View child = getChildAt(i);
        //不可見(jiàn)的跳過(guò)
        if (child.getVisibility() == GONE) {
            continue;
        }
        //測(cè)量一個(gè)子View束世,并處理padding酝陈,margin
        measureChild(child, widthMeasureSpec, heightMeasureSpec);
        FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
        int marginWidth = lp.leftMargin + lp.rightMargin;
        int marginHeight = lp.topMargin + lp.bottomMargin;
        spareWidth += child.getMeasuredWidth() + marginWidth;
        maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + marginHeight);
    }
    //最后來(lái)測(cè)量第一個(gè)View,使用的方式是AT_MOST毁涉,寬度是剩余空間
    View firstChild = getChildAt(0);
    FrameLayout.LayoutParams lp = (LayoutParams) firstChild.getLayoutParams();
    int marginWidth = lp.leftMargin + lp.rightMargin;
    int marginHeight = lp.topMargin + lp.bottomMargin;
    int paddingWidth = getPaddingLeft() + getPaddingRight();
    int paddingHeight = getPaddingTop() + getPaddingBottom();
    int firstViewWidthSpec =
         MeasureSpec.makeMeasureSpec(widthSize - spareWidth - marginWidth - paddingWidth,
            MeasureSpec.AT_MOST);
    measureChild(firstChild, firstViewWidthSpec, heightMeasureSpec);
    maxHeight = Math.max(firstChild.getMeasuredHeight() + marginHeight, maxHeight);
    //儲(chǔ)存測(cè)量結(jié)果
    setMeasuredDimension(spareWidth + firstChild.getMeasuredWidth() + paddingWidth,
        maxHeight + paddingHeight);
}

測(cè)量得到了每一個(gè)View應(yīng)該的大小沉帮,接下來(lái)就是擺放所有的子View,看過(guò)來(lái)onLayout()

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    int left = 0;
    //從左向右排放View
    for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        if (child.getVisibility() == GONE) {
            continue;
        }
        FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
        int leftStart = left + lp.leftMargin + getPaddingLeft();
        int topStart;

        //處理vertical的gravity
        final int verticalGravity = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
        switch (verticalGravity) {
            case Gravity.TOP:
                //從上向下計(jì)算
                topStart = lp.topMargin + getPaddingTop();
                break;
            case Gravity.CENTER_VERTICAL:
                //vertical的居中贫堰,是指view居中(除去這個(gè)SpareLayout的padding和子View的margin居中)
                topStart = (t + getPaddingTop() + lp.topMargin +    //可以放view的空間上邊
                    b - getPaddingBottom() - lp.bottomMargin        //可以放view的空間下邊
                    - child.getMeasuredHeight()) / 2                //中心線
                    - t;                                            //計(jì)算出view的上邊
                break;
            case Gravity.BOTTOM:
                //從下向上算的
                topStart =
                    b - lp.bottomMargin - getPaddingBottom() - child.getMeasuredHeight() - t;
                break;
            default:
                //默認(rèn)是在上面
                topStart = lp.topMargin + getPaddingTop();
        }
        child.layout(leftStart, topStart, leftStart + child.getMeasuredWidth(),
            topStart + child.getMeasuredHeight());
        //累加左邊已經(jīng)使用的空間
        left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
    }
}

這樣實(shí)現(xiàn)的效果:


?文本比較長(zhǎng)的時(shí)候.png

?文本比較短的情況.png

提一些Tips

如果后面幾個(gè)標(biāo)簽已經(jīng)很大的情況沒(méi)有處理
以前為這個(gè)效果試驗(yàn)了各種方式穆壕,跑包的時(shí)間都比停下來(lái)寫這個(gè)控件時(shí)間長(zhǎng)得多,以后注意不要再做這樣的事
使用linearLayout的weight屬性并沒(méi)有成功

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末其屏,一起剝皮案震驚了整個(gè)濱河市喇勋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偎行,老刑警劉巖川背,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贰拿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡渗常,警方通過(guò)查閱死者的電腦和手機(jī)壮不,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)皱碘,“玉大人询一,你說(shuō)我怎么就攤上這事“┐唬” “怎么了健蕊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)踢俄。 經(jīng)常有香客問(wèn)我缩功,道長(zhǎng),這世上最難降的妖魔是什么都办? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任嫡锌,我火速辦了婚禮,結(jié)果婚禮上琳钉,老公的妹妹穿的比我還像新娘势木。我一直安慰自己,他們只是感情好歌懒,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布啦桌。 她就那樣靜靜地躺著,像睡著了一般及皂。 火紅的嫁衣襯著肌膚如雪甫男。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天验烧,我揣著相機(jī)與錄音板驳,去河邊找鬼。 笑死碍拆,一個(gè)胖子當(dāng)著我的面吹牛笋庄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播倔监,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼菌仁!你這毒婦竟也來(lái)了浩习?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤济丘,失蹤者是張志新(化名)和其女友劉穎谱秽,沒(méi)想到半個(gè)月后洽蛀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疟赊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年郊供,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片近哟。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驮审,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吉执,到底是詐尸還是另有隱情疯淫,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布戳玫,位于F島的核電站熙掺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏咕宿。R本人自食惡果不足惜币绩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望府阀。 院中可真熱鬧缆镣,春花似錦、人聲如沸肌似。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)川队。三九已至力细,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間固额,已是汗流浹背眠蚂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斗躏,地道東北人逝慧。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像啄糙,于是被迫代替她去往敵國(guó)和親笛臣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,506評(píng)論 25 707
  • 當(dāng)Android原生控件無(wú)法滿足需求時(shí)就要自定義View诞丽,只有掌握了View的測(cè)量過(guò)程 (measure)鲸拥、布局過(guò)...
    小蕓論閱讀 7,225評(píng)論 7 54
  • 在《世間事》專題改版成《故事》專題之際,也迎來(lái)了《故事?tīng)Z》第十六期僧免。 文友們?cè)陂喿x《故事?tīng)Z》刑赶,參與活動(dòng)的同時(shí),也驚...
    孤獨(dú)一刀閱讀 591評(píng)論 17 19
  • 剛結(jié)婚時(shí)懂衩,兩人的愛(ài)情就像玫瑰花一樣撞叨,熾熱,激情勃痴。 有了孩子以后谒所,兩人的關(guān)系像狂風(fēng)中的纖草,震顫沛申,搖擺劣领。 老了以后,...
    芒果兒閱讀 265評(píng)論 3 3
  • 古殿空山裹铁材,名王有舊塋尖淘。秦陵和漢寢,不及此幽情 仿佛一個(gè)垂垂老矣的劍客著觉,白發(fā)橫額村生,皺紋交錯(cuò),卻掩不住那提劍時(shí)...
    shindowy閱讀 1,008評(píng)論 0 1