android --巧用 flexboxLayout 佈局

前言

某天在作項目的時候,遇到了個看似簡單但又無從下手的小功能,效果相似微信羣聊選擇聯繫人界面: html

在這裏插入圖片描述
有沒有發現選擇人員變更後上面部分的展現是從中間往兩邊擴散的?最開始的時候我是直接用 RecycleView 展現的,就是一再普通不過的九宮格佈局了。在產品的要求下要改爲相似微信的這種佈局,而後我就開始了 「面向搜索引擎」的編程,搜尋了半天,什麼仿微信啊,什麼中間佈局啊(事實證實就算是「面向搜索引擎」的編程,我仍是要學不少,由於,關鍵字定位的不許確),未果。

而後一想,嘿嘿,沒事,輪子沒有本身造唄,一看就得自定義佈局。遂拿起個人小本本,準備大幹一番,用筆寫下思路,磨蹭了十幾分鍾,本子上只有幾個立體幾何。。。(有個小癖好,寫不出來喜歡在本子上畫立方體)。前端

而後想一時半會自定義也掌握很差啊,時間又趕,遂又開始了大規模搜索。在快要放棄的時候看到了這篇文章:Android 彈性佈局 FlexboxLayout瞭解一下 看到其中這張圖的時候,兩眼放光,異常激動啊。 react

圖片來自連接博客
看完是否是感受但願就在前方? 因而看了下 flexboxLayout 的介紹,完徹底全就是前端的 flexbox 佈局啊,連屬性名稱都同樣。由於有點 react native 基礎,因此事情變得 so easy。最後看到居然支持 RecycleView,只需改動極少許的代碼,簡直不能太贊。

嗯,廢話那麼多,鋪墊那麼長,下面來介紹一下今天的主角 : flexboxLayout 。android

首先要作的事情固然是在項目中集成了:git

compile 'com.google.android:flexbox:1.0.0'
複製代碼

1.什麼是 flexboxLayout 佈局?

github.com/google/flex… 項目簡介中是這樣一句話來歸納 flexboxLayout 的:github

FlexboxLayout is a library project which brings the similar capabilities of CSS Flexible Box Layout Module to Android. FlexboxLayout 是一個在 Android 上實現 CSS 的 彈性盒狀佈局 模塊的庫編程

有前端基礎的同窗估計都知道 CSS 中這個佈局,用來爲盒狀模型提供最大的靈活性。由於 android 中這個庫屬性和 CSS 中 都同樣,而且阮一峯老師寫的前端知識真的很通俗易懂,因此這裏的介紹大多來自 Flex 佈局教程segmentfault

在這裏插入圖片描述
採用 Flex 佈局的元素,稱爲 Flex 容器(flex container),簡稱"容器"。它的全部子元素自動成爲容器成員,稱爲 Flex 項目(flex item),簡稱"項目"。

容器默認存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。這裏與 react native 相反,與前端 CSS 保持一致。bash

主軸的開始位置(與邊框的交叉點)叫作main start,結束位置叫作main end;交叉軸的開始位置叫作cross start,結束位置叫作cross end微信

項目默認沿主軸排列。單個項目佔據的主軸空間叫作 main size,佔據的交叉軸空間叫作 cross size。

2.容器的屬性 (FlexboxLayout 屬性介紹)

這裏說的容器也就是上面的採用了 Flex 佈局的元素,在 android 中也就是引用了 FlexboxLayout 的 控件。即 FlexboxLayout 控件支持的屬性。主要屬性有:

在這裏插入圖片描述
各個屬性的詳細含義這裏就再也不贅述,阮一峯老師 這篇文章 寫的超級棒,圖文並茂,很容易理解,推薦你們看一下。

3.項目的屬性 (子 View 屬性介紹)

設置被 FlexboxLayout 包裹的子 View 的屬性,由於 android 中的 flexboxLayout 佈局 和 CSS 中 flex 佈局關於子 View 屬性有些差別,因此這裏詳細說明下,取值以下:

  • layout_order (integer)
  • layout_flexGrow (float)
  • layout_flexGrow (float)
  • layout_alignSelf
  • layout_flexBasisPercent (fraction)
  • layout_minWidth / layout_minHeight (dimension)
  • layout_maxWidth / layout_maxHeight (dimension)
  • layout_wrapBefore (boolean)

下面來看一下github文檔中對這些屬性的描述

3.1 layout_order

這個屬性能夠改變佈局子視圖的順序。默認狀況下,子元素的顯示和佈局順序與佈局XML中的順序相同。若是沒有指定,則將1設置爲默認值( CSS 中默認值爲 0) ,數值越小,排列越靠前

在這裏插入圖片描述
看下文檔中的這張圖,能夠看到將 「2」 號 View 的 layout_order 屬性設置爲 -1時,因爲其餘的 View 默認都是 1,因此 「2」 號 view會排在最前面,同理,將 「2」 號 View 的 layout_order 的屬性值設爲 2 時,比其餘默認值 1 都大,因此會排在最後。

3.2 layout_flexGrow

這個屬性相似於 LinearLayout 中的 layout_weight 屬性,若是沒有指定,則將 0 設置爲默認值。若是果同一 flex 行中的多個子 View 有正的 layout_flexGrow 值,那麼剩餘的空閒空間將根據它們聲明的 layout_flexGrow 值的比例分佈。

3.3 layout_flexShrink

該屬性定義了子 View 的縮小比例,默認爲 1,即若是空間不足,該子 View 將縮小。 若是全部子 View 的 layout_flexShrink 屬性都爲 1,當空間不足時,都將等比例縮小。若是一個項目的 layout_flexShrink 屬性爲0,其餘子View都爲 1,則空間不足時,layout_flexShrink 屬性爲 0 的不縮小。

在這裏插入圖片描述
看一下文檔中的這張圖,開始設置全部子 view 的 layout_flexShrink 屬性爲1,添加子 view 的時候全部子 view 等比縮小,可是若是設置 layout_flexShrink 屬性值爲 0,子 view 將會按照原有比例顯示,不縮小。

3.4 layout_alignSelf

layout_alignSelf 屬性容許單個子 View 有與其餘 View 不同的對齊方式,可覆蓋 align-items 屬性。默認值爲 auto,表示繼承父元素的 align-items 屬性,若是沒有父元素,則等同於 stretch。 該屬性可能取 6 個值,除了 auto,其餘都與 align-items 屬性徹底一致

3.5 layout_flexBasisPercent

flex-layout_flexBasisPercent 屬性定義了在分配多餘空間以前,子 View 佔據的主軸空間(main size)。根據這個屬性來計算主軸是否有多餘空間。它的默認值爲 -1,即不設置,採用子 View 的原本大小。

若是設置了這個值,layout_width (或 layout_height )中指定的長度將被該屬性的計算值覆蓋。這個屬性只有在父 View 的長度是肯定的時候纔有效(測量模式是 MeasureSpec.EXACTLY 模式下)。 而且該屬性值只接受百分比值。

在這裏插入圖片描述
能夠分析下文檔中的這張圖:能夠看到,若是把中間子 View 的這個屬性值設爲 50% 或 90%,那麼這個 View 將佔據主軸 50% 或 90% 的空間,而後剩餘 View 會看有沒有剩餘空間換行。若是設置爲 -1 默認值,那麼將佔據給定的大小。

3.6 layout_minWidth / layout_minHeight

這個屬性設置了子 View 的最小的寬和高。在 layout_flexShrink 模式下,再怎麼縮小也不會小於這個值

3.7 layout_maxWidth / layout_maxHeight

這個屬性設置了子 View 的最大的寬和高。在 layout_flexGrow 模式下,再怎麼放大也不會大於這個值

3.8 layout_wrapBefore

這個屬性使得子 View 能夠強制換行,無論在 main size 剩餘空間有多少。這種對於相似 grid 網格佈局中特殊設置某一個 item 佈局特別有用。 這個屬性是 CSS 中沒有的屬性。該屬性在 flex_wrap 屬性值 爲 nowrap(不換行)的時候是無效的。 該屬性結束 boolean 變量,默認 false,即不強制換行

在這裏插入圖片描述
分析下文檔中的這張圖,「5」 號和 「6」 號 View 設置 layout_wrapBefore 屬性爲ture 的時候,無論前面剩餘多少空間,都會強制換行

到這裏,flexboxLayout 基本屬性就介紹完畢了。

而後再來介紹一下跟 recycleView 結合使用。

4. 高能:與 RecyclewView 結合使用

Flexbox 可以做爲一個 LayoutManager(FlexboxlayoutManager) 用在 RecyclerView 裏面,這也就意味着你能夠在一個有大量 Item 的可滾動容器裏面使用 Flexbox,提升性能。具體使用示例:

//設置主軸方向爲橫軸
        FlexboxLayoutManager manager = new FlexboxLayoutManager(this, FlexDirection.ROW);
        //設置item沿主軸方向的位置
        manager.setJustifyContent(JustifyContent.CENTER);
        //設置item 沿次軸方向的位置
        manager.setAlignItems(AlignItems.CENTER);

        recycleView.setLayoutManager(manager);
        centerGridAdapter = new CenterGridAdapter(items, this);
        recycleView.setAdapter(centerGridAdapter);
複製代碼

能夠看到跟 RecycleView 的其餘 manager 使用同樣,只需設置 manager 屬性便可,屬性值爲上面敘述的幾個容器的屬性。 若是想對某個 item 進行單獨的設置,能夠在 adapter 中去設置,設置示例代碼爲:

ViewGroup.LayoutParams lp =  holder.itemLL.getLayoutParams();
        if (lp instanceof FlexboxLayoutManager.LayoutParams) {
            FlexboxLayoutManager.LayoutParams flexboxLp =
                    (FlexboxLayoutManager.LayoutParams)  holder.itemLL.getLayoutParams();
            flexboxLp.setFlexGrow(1.0f);
        }
複製代碼

我這裏是設置每一個 item 有個權重(至關於 Linearlayout 的 weight 屬性),因此會按比例分配 item 的寬,而不是我佈局中設定的固定寬高。看下效果:

在這裏插入圖片描述

是否是有種鍵盤的感受?而且我只是修改了極少的代碼就實現了這個功能。

小試牛刀1

最後,看了那麼多,回到最開始的問題上,如今知道相似微信的那個中間擴展的網格佈局怎麼寫的嗎? 首先咱們簡單分析一下,

  • 主軸方向咱們應該設置爲水平方向,即默認 flexDirection :「row」’
  • 能夠換行,即 flexWrap:「wrap」
  • 子 View 在主軸方向的對其方式爲居中(這一步實現從中間往兩邊展開),即 justifyContent: "center"
  • 子 View 在交叉軸方向的對其方式爲居中,即 alignItems:"center"
  • 子 View 寬高固定

也就是上面講 Recycleview 結合的例子中去掉單獨設置 item 的部分,而且 item 的寬高要根據屏幕來適配的。 嗯,就是 so easy。

小試牛刀2

在這裏插入圖片描述
實際應用中還有種很常見的就是那種分類選擇的佈局,像圖中的網易和簡書中,這種佈局用咱們今天的這個主角是否是垂手可得的就實現了?都不用設置特別的屬性,內容超過一行自動換行。 代碼以下:

//設置主軸方向爲橫軸
        FlexboxLayoutManager manager = new FlexboxLayoutManager(this, FlexDirection.ROW);
        //設置item沿主軸方向的位置
        manager.setJustifyContent(JustifyContent.FLEX_START);
        //設置item 沿次軸方向的位置
        manager.setAlignItems(AlignItems.CENTER);

        recycleView.setLayoutManager(manager);
        labelAdapter = new LabelAdapter(labels,this);
        recycleView.setAdapter(labelAdapter);
複製代碼

總結

因此說了這麼多,那麼咱們何時會用到這種佈局呢?我目前想到的場景主要有 3 類:

  1. 相似LinearLayout 線性佈局,可是又能夠自動換行的
  2. 相似grid 網格佈局的,但總有一兩個item的排列方式很特立獨行的
  3. 相似瀑布流的,但也是總有一兩個item跟別人不同的

固然這些場景加上 RecycleView 就會更加暢享絲滑了。

demo 傳送門

參考

阮一峯:Flex 佈局教程:語法篇 flexbox-layout 的 github 地址

相關文章
相關標籤/搜索