百分比佈局標籤佈局之FlexBoxLayout

最近在看google的demo,想逼着自己看源碼,所以,今天來看看FlexBoxLayout,起初第一次用Flex佈局的時候還是在學習react native的時候(雖然現在都好久沒玩過了-_-!),今天把google的demo順着自己的想法又重新敲了一遍,把玩之後看了下源碼,確實是有點複雜啊,每個步驟都要進行各種分類,想想那麼多的佈局種類,往下看的時候我都差點放棄了(基礎不好啊),隨後會附上demo,比google demo簡單好理解。

佈局控制的5大屬性

flexDirection

  1. row (default)
  2. row_reverse
  3. column
  4. column_reverse

根據官網給的理解就是這個屬性決定了佈局主軸的方向。首先來看看gif圖

這裏寫圖片描述

從圖中就可以看出
row開頭的是決定了佈局的item沿着橫軸進行變化,row是沿着左頂點(left)進行順序排序,row_reverse沿着右頂點(right)進行反序進行排序

column開頭的決定了佈局的item沿着縱軸進行變化,column是沿着上頂點(top)進行順序排序,column_reverse是沿着下頂點(bottom)進行反序排序。

也就是說,flexDirection這個屬性決定了items在佈局的方向。

flexWrap

  1. nowrap (default)
  2. wrap
  3. wrap_reverse

根據官網意思看,這個屬性控制了items們在橫軸方向上是單行還是多行。看看gif圖

這裏寫圖片描述

這個屬性很有意思:
設置nowrap的時候有點像LinearLayout的子view的寬度或高度設置了weight,大家在一行平均分寬度,

設置wrap,那就有點像我們android開發的時候經常會使用到的標籤控件啦—流式佈局,按控件的寬度一個個排列,大於整體寬度的時候就換行,看源碼知道,在onMeasure的時候就已經計算好了一行有多少個item,每一行都是用FlexLine去存儲,FlexLine裏面存儲了這一行有多少個mItemCount,還有left,top,right,bottom等等參數信息。

設置wrap_reverse,將item的設置在佈局的底部,然後將每一行進行反轉,行內的items不進行排序,按照原來輸出,這個行也是很有意思的,根據源碼裏面所示, List mFlexLines = new ArrayList<>();存儲了所有的行,FlexLine存儲了每一行中的item的數目,還有item的各種LayoutParame參數,在給flexWrap設置wrap_reverse的時候,他是從底部開始佈局,看代碼,每一次佈局都是從佈局底部減去控件的高度來拿到item的top,也就是item放在最後一行,以此類推。

 if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {

                  //FlexWrap是FLEX_WRAP_WRAP_REVERSE 並且Direction按Column排列
                    if (isRtl) {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childRight) - child.getMeasuredWidth(),
                                childBottom - child.getMeasuredHeight(), Math.round(childRight),
                                childBottom);
                  //是FLEX_WRAP_WRAP_REVERSE 並且Direction按行ROW排列
                    } else {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childLeft), childBottom - child.getMeasuredHeight(),
                                Math.round(childLeft) + child.getMeasuredWidth(),
                                childBottom);
                    }
                } else {
                //FlexWrap是Wrap或是NoWrap,並且Direction按Column排列
                    if (isRtl) {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childRight) - child.getMeasuredWidth(), childTop,
                                Math.round(childRight), childTop + child.getMeasuredHeight());
                //FlexWrap是Wrap或是NoWrap,並且Direction按ROW排列                
                    } else {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childLeft), childTop,
                                Math.round(childLeft) + child.getMeasuredWidth(),
                                childTop + child.getMeasuredHeight());
                    }
                }

justifyContent

  1. flex_start (default)
  2. flex_end
  3. center
  4. space_between
  5. space_around

官網的意思是這個屬性控制沿着主軸對齊,也就是說,當flexDirection設置ROW的時候,主軸就是行,按行進行對齊,如果flexDirection設置的是Column,主軸就是列,那就按列進行對齊,看gif圖


一、當flexDirection設置ROW,主軸是按行的時候

這裏寫圖片描述

從gif中可以看出,當FlexWrap設置爲wrap的時候
1. flex_start 就相當於左對齊,
2. flex_end相當於右對齊
3. center相當於居中對齊
4. space_between相當於兩端對齊
5. space_around相當於分散對齊
當FlexWrap設置爲NoWrap的時候,這個就要分情況了,當佈局有剩餘部分的時候,跟上面功能一樣,當佈局已經把剩餘空間填滿了,那justifyContent就相當於無效了,這個也很好理解,沒有空間也就沒有對其分配了。

二、當flexDirection設置ROW,主軸是按行的時候

這裏寫圖片描述

和上面主軸爲row的情況一樣,當FlexWrap設置爲NoWrap,並且沒有剩餘空間的時候,也是不起作用的

alignItems

  1. stretch (default)
  2. flex_start
  3. flex_end
  4. center
  5. baseline

官網介紹,此屬性控制沿橫軸的對齊方式,意思其實就是如果當前Direction爲ROW,比如一行items,可以放在最上面,也可以放在最下面,中間等等。如果Direction爲column,items就可以放在最左邊、中間、或是右邊等等。

這個地方要分兩種情況來看待了
下面的gif是Direction設置ROW,FlexWrap設置NoWrap(justifyContent先不看了,上面說了,當FlexWrap設置NoWrap,並且無剩餘空間的時候,justifyContent是不起效果的,所以justifyContent就看做默認值爲Flex Start,雖然FlexWrap設置爲Wrap,justifyContent是可以使用對齊方式的,但是,在對alignItems設置屬性的時候,佈局幾乎是不動的,只有baseline基準線稍微對齊了下,所以,在這個地方設置justifyContent有點矛盾,所以,就把他看做默認值來看吧,當然,如果你設置FlexWrap設置Wrap肯定是可以使用的,因爲有了空餘空間,justifyContent就能對空餘控件進行對齊操作),然後對alignItems進行測試

這裏寫圖片描述
測試結果可以發現FlexWrap設置Wrap的時候,alignItems的屬性幾乎對佈局不起作用,唯一動的就是Baseline基準線動了一下,這也就是我爲什麼設置justifyContent爲默認值的原因了。

結果顯示:
1. stretch 有點像weight,填充縱向的剩餘部分
2. flex_start 行頂部對齊
3. flex_end 行底部對齊
4. center 行居中對齊
5. baseline 行內的文字進行基準線對齊

Direction設置Column,FlexWrap設置NoWrap,然後對alignItems進行測試就不演示了,和上面一樣,只不過是在column方向進行改變,gif就不貼了,大家可以下載下demo把玩,我把結果貼出來
結果顯示:
1. stretch 有點像weight,填充橫向的剩餘部分
2. flex_start 列左部對齊
3. flex_end 列右部對齊
4. center 列居中對齊
5. baseline 無效

alignContent

  1. stretch (default)
  2. flex_start
  3. flex_end
  4. center
  5. space_between
  6. space_around

官網介紹,此屬性控制Flex容器中的Flex行的對齊方式

在上面alginItems的介紹中,我們在實踐中發現,Direction設置ROW,FlexWrap設置Wrap,justifyContent爲默認值,這個控件幾乎是不能參與對齊,只有當FlexWrap設置爲NoWrap,alginItems纔可以進行控制,但是,我現在想去控制佈局怎麼辦呢?這時候alignContent就完成這一步驟,當FlexWrap設置Wrap,alignContent可以來改變,這裏面有一個好玩的地方,就是其他的設置爲默認,
一、如果FlexWrap設置爲Wrap,alignContent可以控制,alginItems不能控制。
二、如果FlexWrap設置爲NoWrap,alignContent不能控制,alginItems可以控制。
這樣的特點就完全解決了我上面所說的矛盾。
來看gif,
這裏寫圖片描述

showDivider屬性

這個屬性描述了FlowBoxLayout中,各個子view之間的用什麼線條,和ListView的divider有點像。

來看看有多少個控制屬性

  1. showDividerHorizontal (one or more of none | beginning | middle | end)
  2. dividerDrawableHorizontal (reference to a drawable)
  3. showDividerVertical(one or more of none | beginning | middle | end)
  4. dividerDrawableVertical (reference to a drawable)
  5. showDivider (one or more of none | beginning | middle | end)
  6. dividerDrawable (reference to a drawable)

dividerDrawableHorizontal(將水平分隔線放在伸縮線之間)

該屬性的參數爲一個drawable,配合showDivider或者showDividerHorizontal一起使用纔會顯示線條,其他顯示效果無效

showDividerHorizontal

showDividerHorizontal有none | beginning | middle | end四個屬性,none就是不顯示線條,beginning顯示線條在佈局的上面,end顯示線條在佈局的下面,middle顯示線條佈局除上頭和下的其他水平空隙

dividerDrawableVertical(將垂直分隔線放在伸縮線之間)

該屬性的參數爲一個drawable,配合showDivider或者showDividerVertical一起使用纔會顯示線條,其他顯示效果無效

showDividerVertical

showDividerVertical有none | beginning | middle | end四個屬性,none就是不顯示線條,beginning顯示線條在佈局的左邊,end顯示線條在佈局的右邊,middle顯示線條佈局除去左和右的其他垂直空隙

dividerDrawable

該屬性的參數爲一個drawable,配合showDivider可以顯示水平和垂直方向的線條,如果配合的是showDividerVertical,和showDividerVertical效果一樣,只對垂直部分起作用,水平不起作用,如果配合的是showDividerHorizontal,和showDividerHorizontal效果一樣,只對水平部分起作用,垂直不起作用,

showDivider

showDivider有none | beginning | middle | end四個屬性,
配合dividerDrawableHorizontal就是showDividerHorizontal的效果,配合dividerDrawableVertical就是showDividerVertical的效果,配合dividerDrawable就是顯示水平和垂直方向的線條

layout_order

這個屬性是給子view設置的,按我的理解來的話,就是給view進行排序,誰的order權重大,誰就排後面,以此類推,如果沒有設置order的話,那就按默認排列,

xml佈局文件,該佈局1和10我沒有設置oder

com.google.android.flexbox.FlexboxLayout
        android:id="@+id/flexbox"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:alignContent="flex_start"
        app:alignItems="flex_start"
        app:flexWrap="wrap">

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:padding="3dp"
            android:text="1"
            android:textSize="20dp" />

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="2"
            android:textSize="20dp"
            app:layout_order="2" />

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="3"
            android:textSize="20dp"
            app:layout_order="3" />

        <TextView
            android:layout_width="110dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="4"
            android:textSize="20dp"
            app:layout_order="4" />

        <TextView
            app:layout_order="5"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="5"
            android:textSize="20dp" />

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="6"
            android:textSize="20dp"
            app:layout_order="6" />

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="7"
            android:textSize="20dp"
            app:layout_order="7" />

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="8"
            android:textSize="20dp"
            app:layout_order="8" />

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="9"
            android:textSize="20dp"
            app:layout_order="9" />

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="10"
            android:textSize="20dp" />
    </com.google.android.flexbox.FlexboxLayout>

我們來看看gif,看看那一個好玩的東西。

這裏寫圖片描述

當我們點擊減少佈局的時候發現,9是最後一個佈局,應該點擊刪除的是9佈局,但是刪除的缺卻是佈局10,從這一點,我們可以推敲出,在該類中,並沒有對整體的view進行排序,view還是按照原來的方式排列。

layout_flexGrow

這個參數有點像LinearLayout的weight,就是一行的數據,如果有空隙的話,他會自動增長填補空隙,默認值爲1,現在,我們還是用上面的佈局,我們給佈局1和佈局2設置相同的layout_flexGrow爲2,我們來看看gif效果

這裏寫圖片描述
從這個效果中我們看到,在刪除的過程中,1和2都會自動的填充空餘部分,並且1和2設置的都是相同的權值,那他們的增長也是一樣的,添加也是一樣,添加進來的view,1和2會同時一樣的寬度進行縮小

layout_flexShrink

這個屬性決定這個孩子如果在同一個Flex中包含的其他Flex項目的剩餘自由空間被分配的時候會收縮多少

還是上面的佈局,我們給佈局1設置layout_flexShrink爲20,給佈局2設置layout_flexShrink爲100,來看看gif

這裏寫圖片描述

增加子view的時候,首先會把設置layout_flexShrink最大的佈局2先當做空餘空間佔用,然後再來佔用佈局1

layout_minWidth / layout_minHeight

在NoWrap下,我們在增加子view的時候,其他view會伸縮自己寬度爲給新進來的子view分配空餘空間,假如,我們要其中的一個view不讓他隨着新進來的view而改變自己的寬度呢,這時候,我們在Direction爲Row,FlexWrap爲NoWrap的時候設置layout_minWidth爲自己至少想要的寬度,在Direction爲Column,FlexWrap爲NoWrap的時候設置layout_minHeight爲自己至少想要的高度,這樣,在新進來的子view就不會擠壓這個view了


        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:padding="3dp"
            android:text="1"
            android:textSize="20dp"

            app:layout_minHeight="20dp"
            />

layout_flexBasisPercent

這個屬性是我這個裏面看的最喜歡的屬性了,對android適配簡直好的沒話講,這個屬性看名字就知道了,百分比佈局,就是對佈局子view的排列,我們可以按照百分比的樣式進行排放子view,那對於在android上的適配可以做到特別好的幫助。

該屬性默認值爲-1,此屬性僅在父長度確定時纔有效(MeasureSpec mode is MeasureSpec.EXACTLY),意思就是match_parent或是指定高度或是寬度的時候,這個屬性就能發揮他的作用。

我們設置先設置FlexWrap爲Wrap,佈局1的FlexBoxLayout爲50,佈局2的FlexBoxLayout爲30,佈局2的FlexBoxLayout設置爲20,剛好100%,那麼接下來其他的子view肯定會換行,我們來看看效果

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:padding="3dp"
            android:text="1"
            app:layout_flexBasisPercent="50%"
            android:textSize="20dp" />

        <TextView
            app:layout_flexBasisPercent="30%"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="2"
            android:textSize="20dp" />

        <TextView
            app:layout_flexBasisPercent="20%"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="3"
            android:textSize="20dp" />

這裏寫圖片描述

正如我們自己所推想的,還是挺不錯的一個功能。


從早上一邊寫一邊看官網,一邊測試,寫一篇博客還是挺耗時間的,但是卻樂此不疲

github demo鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章