日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Android 巧用 flexboxLayout 布局

發(fā)布時(shí)間:2024/3/13 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 巧用 flexboxLayout 布局 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

FlexBoxlayout是Google推出的開源的可伸縮性布局,在項(xiàng)目中也會(huì)經(jīng)場(chǎng)使用,大大提高了用戶的體驗(yàn)。

compile 'com.google.android:flexbox:1.0.0'

有前端基礎(chǔ)的同學(xué)估計(jì)都知道 CSS 中這個(gè)布局,用來(lái)為盒狀模型提供最大的靈活性。因?yàn)?android 中這個(gè)庫(kù)屬性和 CSS 中 都一樣,并且阮一峰老師寫的前端知識(shí)真的很通俗易懂,所以這里的介紹大多來(lái)自?Flex 布局教程。

采用 Flex 布局的元素,稱為 Flex 容器(flex container),簡(jiǎn)稱”容器”。它的所有子元素自動(dòng)成為容器成員,稱為 Flex 項(xiàng)目(flex item),簡(jiǎn)稱”項(xiàng)目”。

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

主軸的開始位置(與邊框的交叉點(diǎn))叫做main start,結(jié)束位置叫做main end;交叉軸的開始位置叫做cross start,結(jié)束位置叫做cross end

項(xiàng)目默認(rèn)沿主軸排列。單個(gè)項(xiàng)目占據(jù)的主軸空間叫做 main size,占據(jù)的交叉軸空間叫做 cross size。

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

這里說(shuō)的容器也就是上面的采用了 Flex 布局的元素,在 android 中也就是引用了 FlexboxLayout 的 控件。即 FlexboxLayout 控件支持的屬性。主要屬性有:


各個(gè)屬性的詳細(xì)含義這里就不再贅述,阮一峰老師?這篇文章?寫的超級(jí)棒,圖文并茂,很容易理解,推薦大家看一下。

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

設(shè)置被 FlexboxLayout 包裹的子 View 的屬性,因?yàn)?android 中的 flexboxLayout 布局 和 CSS 中 flex 布局關(guān)于子 View 屬性有些差異,所以這里詳細(xì)說(shuō)明下,取值如下:

  • 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)

下面來(lái)看一下github文檔中對(duì)這些屬性的描述

3.1 layout_order

這個(gè)屬性可以改變布局子視圖的順序。默認(rèn)情況下,子元素的顯示和布局順序與布局XML中的順序相同。如果沒有指定,則將1設(shè)置為默認(rèn)值( CSS 中默認(rèn)值為 0) ,數(shù)值越小,排列越靠前


看下文檔中的這張圖,可以看到將 “2” 號(hào) View 的 layout_order 屬性設(shè)置為 -1時(shí),由于其他的 View 默認(rèn)都是 1,所以 “2” 號(hào) view會(huì)排在最前面,同理,將 “2” 號(hào) View 的 layout_order 的屬性值設(shè)為 2 時(shí),比其他默認(rèn)值 1 都大,所以會(huì)排在最后。

3.2 layout_flexGrow

這個(gè)屬性類似于 LinearLayout 中的?layout_weight?屬性,如果沒有指定,則將 0 設(shè)置為默認(rèn)值。如果果同一 flex 行中的多個(gè)子 View 有正的 layout_flexGrow 值,那么剩余的空閑空間將根據(jù)它們聲明的 layout_flexGrow 值的比例分布。

3.3 layout_flexShrink

該屬性定義了子 View 的縮小比例,默認(rèn)為 1,即如果空間不足,該子 View 將縮小。
如果所有子 View 的 layout_flexShrink 屬性都為 1,當(dāng)空間不足時(shí),都將等比例縮小。如果一個(gè)項(xiàng)目的 layout_flexShrink 屬性為0,其他子View都為 1,則空間不足時(shí),layout_flexShrink 屬性為 0 的不縮小。


看一下文檔中的這張圖,開始設(shè)置所有子 view 的 layout_flexShrink 屬性為1,添加子 view 的時(shí)候所有子 view 等比縮小,但是如果設(shè)置 layout_flexShrink 屬性值為 0,子 view 將會(huì)按照原有比例顯示,不縮小。

3.4 layout_alignSelf

layout_alignSelf 屬性允許單個(gè)子 View 有與其他 View 不一樣的對(duì)齊方式,可覆蓋 align-items 屬性。默認(rèn)值為 auto,表示繼承父元素的 align-items 屬性,如果沒有父元素,則等同于 stretch。
該屬性可能取 6 個(gè)值,除了 auto,其他都與 align-items 屬性完全一致

3.5 layout_flexBasisPercent

flex-layout_flexBasisPercent 屬性定義了在分配多余空間之前,子 View 占據(jù)的主軸空間(main size)。根據(jù)這個(gè)屬性來(lái)計(jì)算主軸是否有多余空間。它的默認(rèn)值為 -1,即不設(shè)置,采用子 View 的本來(lái)大小。

如果設(shè)置了這個(gè)值,layout_width (或 layout_height )中指定的長(zhǎng)度將被該屬性的計(jì)算值覆蓋。這個(gè)屬性只有在父 View 的長(zhǎng)度是確定的時(shí)候才有效(測(cè)量模式是 MeasureSpec.EXACTLY 模式下)。
并且該屬性值只接受百分比值。


可以分析下文檔中的這張圖:可以看到,如果把中間子 View 的這個(gè)屬性值設(shè)為 50% 或 90%,那么這個(gè) View 將占據(jù)主軸 50% 或 90% 的空間,然后剩余 View 會(huì)看有沒有剩余空間換行。如果設(shè)置為 -1 默認(rèn)值,那么將占據(jù)給定的大小。

3.6 layout_minWidth / layout_minHeight

這個(gè)屬性設(shè)置了子 View 的最小的寬和高。在 layout_flexShrink 模式下,再怎么縮小也不會(huì)小于這個(gè)值

3.7 layout_maxWidth / layout_maxHeight

這個(gè)屬性設(shè)置了子 View 的最大的寬和高。在 layout_flexGrow 模式下,再怎么放大也不會(huì)大于這個(gè)值

3.8 layout_wrapBefore

這個(gè)屬性使得子 View 可以強(qiáng)制換行,不管在 main size 剩余空間有多少。這種對(duì)于類似 grid 網(wǎng)格布局中特殊設(shè)置某一個(gè) item 布局特別有用。
這個(gè)屬性是 CSS 中沒有的屬性。該屬性在 flex_wrap 屬性值 為 nowrap(不換行)的時(shí)候是無(wú)效的。
該屬性結(jié)束 boolean 變量,默認(rèn) false,即不強(qiáng)制換行


分析下文檔中的這張圖,“5” 號(hào)和 “6” 號(hào) View 設(shè)置 layout_wrapBefore 屬性為ture 的時(shí)候,不管前面剩余多少空間,都會(huì)強(qiáng)制換行

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

然后再來(lái)介紹一下跟 recycleView 結(jié)合使用。

4. 高能:與 RecyclewView 結(jié)合使用

Flexbox 能夠作為一個(gè) LayoutManager(FlexboxlayoutManager) 用在 RecyclerView 里面,這也就意味著你可以在一個(gè)有大量 Item 的可滾動(dòng)容器里面使用 Flexbox,提高性能。具體使用示例:

1 2 3 4 5 6 7 8 9 10 //設(shè)置主軸方向?yàn)闄M軸 FlexboxLayoutManager manager = new FlexboxLayoutManager(this, FlexDirection.ROW); //設(shè)置item沿主軸方向的位置 manager.setJustifyContent(JustifyContent.CENTER); //設(shè)置item 沿次軸方向的位置 manager.setAlignItems(AlignItems.CENTER);recycleView.setLayoutManager(manager); centerGridAdapter = new CenterGridAdapter(items, this); recycleView.setAdapter(centerGridAdapter);

可以看到跟 RecycleView 的其他 manager 使用一樣,只需設(shè)置 manager 屬性即可,屬性值為上面敘述的幾個(gè)容器的屬性。
如果想對(duì)某個(gè) item 進(jìn)行單獨(dú)的設(shè)置,可以在 adapter 中去設(shè)置,設(shè)置示例代碼為:

1 2 3 4 5 6 ViewGroup.LayoutParams lp = holder.itemLL.getLayoutParams();if (lp instanceof FlexboxLayoutManager.LayoutParams) {FlexboxLayoutManager.LayoutParams flexboxLp =(FlexboxLayoutManager.LayoutParams) holder.itemLL.getLayoutParams();flexboxLp.setFlexGrow(1.0f);}

我這里是設(shè)置每個(gè) item 有個(gè)權(quán)重(相當(dāng)于 Linearlayout 的 weight 屬性),所以會(huì)按比例分配 item 的寬,而不是我布局中設(shè)定的固定寬高。看下效果:

是不是有種鍵盤的感覺?并且我只是修改了極少的代碼就實(shí)現(xiàn)了這個(gè)功能。

小試牛刀1

最后,看了那么多,回到最開始的問題上,現(xiàn)在知道類似微信的那個(gè)中間擴(kuò)展的網(wǎng)格布局怎么寫的嗎?
首先我們簡(jiǎn)單分析一下,

  • 主軸方向我們應(yīng)該設(shè)置為水平方向,即默認(rèn) flexDirection :“row”’
  • 可以換行,即 flexWrap:“wrap”
  • 子 View 在主軸方向的對(duì)其方式為居中(這一步實(shí)現(xiàn)從中間往兩邊展開),即 justifyContent: “center”
  • 子 View 在交叉軸方向的對(duì)其方式為居中,即 alignItems:”center”
  • 子 View 寬高固定

也就是上面講 Recycleview 結(jié)合的例子中去掉單獨(dú)設(shè)置 item 的部分,并且 item 的寬高要根據(jù)屏幕來(lái)適配的。
嗯,就是 so easy。

小試牛刀2


實(shí)際應(yīng)用中還有種很常見的就是那種分類選擇的布局,像圖中的網(wǎng)易和簡(jiǎn)書中,這種布局用我們今天的這個(gè)主角是不是輕而易舉的就實(shí)現(xiàn)了?都不用設(shè)置特別的屬性,內(nèi)容超過一行自動(dòng)換行。
代碼如下:

1 2 3 4 5 6 7 8 9 10 //設(shè)置主軸方向?yàn)闄M軸FlexboxLayoutManager manager = new FlexboxLayoutManager(this, FlexDirection.ROW);//設(shè)置item沿主軸方向的位置manager.setJustifyContent(JustifyContent.FLEX_START);//設(shè)置item 沿次軸方向的位置manager.setAlignItems(AlignItems.CENTER);recycleView.setLayoutManager(manager);labelAdapter = new LabelAdapter(labels,this);recycleView.setAdapter(labelAdapter);

小試牛刀3

以項(xiàng)目需求為例,如圖所示:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? ? ? ? ? ? ? ? ? ? ? ? ??

在第一張需求圖中,品牌篩選時(shí) 最后有一個(gè)”+“號(hào),想要的效果時(shí) 根據(jù)品牌選擇后,這個(gè)”+“號(hào)會(huì)緊挨著顯示,如果顯示不完,就換行顯示。

剛開始考慮的是的在RecyclerView添加FooterView,FooterView為一個(gè)“+”的按鈕,這個(gè)按鈕會(huì)換一行顯示,不能緊挨著顯示,如果超過一行再換行顯示。

此時(shí)會(huì)遇到兩個(gè)問題,

按照RecyclerView中的基本用法使用后 會(huì)報(bào)錯(cuò),日志如下:

ClassCastException: android.support.v7.widget.RecyclerView$LayoutParams cannot be cast to com.google.android.flexbox.FlexItem。

我們添加的FooterView,無(wú)法轉(zhuǎn)換成FlexlItem。網(wǎng)上找到解決方案,詳情見FlexboxLayoutManager 踩坑。

一是需要重寫FlexboxLayoutManager,代碼示例如下:
?

import com.google.android.flexbox.FlexboxLayoutManagerclass MyFlexboxLayoutManager : FlexboxLayoutManager {constructor(context: Context) : super(context)constructor(context: Context, flexDirection: Int) : super(context, flexDirection)constructor(context: Context, flexDirection: Int, flexWrap: Int) : super(context, flexDirection, flexWrap)/*** 將LayoutParams轉(zhuǎn)換成新的FlexboxLayoutManager.LayoutParams*/override fun generateLayoutParams(lp: ViewGroup.LayoutParams): RecyclerView.LayoutParams {return when (lp) {//TODO:可能需要適配,特殊處理"+"的寬度is RecyclerView.LayoutParams -> LayoutParams(lp)is ViewGroup.MarginLayoutParams -> LayoutParams(lp)else -> LayoutParams(lp)}} }

第二個(gè)問題:顯示問題。此時(shí)會(huì)出現(xiàn)我們的FooterView(”+“號(hào))換一行顯示,不能緊挨著顯示。

于是陷入思考,在上述代碼中,RecyclerView.LayoutParams的計(jì)算方法LayoutParams(lp)也需要重寫。

在查閱資料和源碼后發(fā)現(xiàn)比較麻煩,最后在網(wǎng)友的幫助下(FlexboxLayoutManager 踩坑),換一種思路,用RecyclerView多布局來(lái)實(shí)現(xiàn),豁然開朗。

思路如下:在數(shù)據(jù)實(shí)體類中添加一個(gè)標(biāo)志,如是否是添加標(biāo)志isAdd,根據(jù)該值的是不同顯示不同的item布局。

class CameraVehicleBrandAdapter : MyBaseMultiItemAdapter<CameraVehicleBrandEntity>() {init {addItemType(CameraVehicleBrandEntity.ITEM_TYPE_NORMAL, R.layout.home_recycle_item_camera_vehicle_brand_selected)addItemType(CameraVehicleBrandEntity.ITEM_TYPE_ADD, R.layout.home_recycle_item_camera_vehicle_brand_add)}override fun convert(helper: BaseViewHolder, item: CameraVehicleBrandEntity) {super.convert(helper, item)if (item.isAdd) {helper.addOnClickListener(R.id.ivAddBrand)return}helper.setText(R.id.tvBrandName, item.brandName)helper.addOnClickListener(R.id.ivDelete)} }

調(diào)用方法:

//品牌篩選 rvBrand.layoutManager = FlexboxLayoutManager(context) rvBrand.adapter = brandAdapter

總結(jié)

所以說(shuō)了這么多,那么我們什么時(shí)候會(huì)用到這種布局呢?我目前想到的場(chǎng)景主要有 3 類:

  • 類似LinearLayout 線性布局,但是又可以自動(dòng)換行的
  • 類似grid 網(wǎng)格布局的,但總有一兩個(gè)item的排列方式很特立獨(dú)行的
  • 類似瀑布流的,但也是總有一兩個(gè)item跟別人不一樣的
  • 當(dāng)然這些場(chǎng)景加上 RecycleView 就會(huì)更加暢享絲滑了。

    demo地址:https://github.com/xiaxiayang/YX_FlexboxLayout

    總結(jié)

    以上是生活随笔為你收集整理的Android 巧用 flexboxLayout 布局的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。