FlexboxLayout
本文是官方文档的翻译
FlexboxLayout 是一个库项目,能在Android上实现类似CSS Flexible Box Layout Module 的能力。
添加以下依赖到你的build.gradle
文件中:
dependencies { implementation 'com.google.android:flexbox:1.0.0' }
在布局中有两种方式使用FlexBox
FlexboxLayout
第一种是像LinearLayout
和 RelativeLayout
那样,FlexboxLayout
都是继承了 ViewGroup
。
你可以指定属性在一个布局XML,如:
<com.google.android.flexbox.FlexboxLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" app:flexWrap="wrap" app:alignItems="stretch" app:alignContent="stretch" > <TextView android:id="@+id/textview1" android:layout_width="120dp" android:layout_height="80dp" app:layout_flexBasisPercent="50%" /> <TextView android:id="@+id/textview2" android:layout_width="80dp" android:layout_height="80dp" app:layout_alignSelf="center" /> <TextView android:id="@+id/textview3" android:layout_width="160dp" android:layout_height="80dp" app:layout_alignSelf="flex_end" /> </com.google.android.flexbox.FlexboxLayout>
或者通过代码像:
FlexboxLayout flexboxLayout = (FlexboxLayout) findViewById(R.id.flexbox_layout); flexboxLayout.setFlexDirection(FlexDirection.ROW); View view = flexboxLayout.getChildAt(0); FlexboxLayout.LayoutParams lp = (FlexboxLayout.LayoutParams) view.getLayoutParams(); lp.order = -1; lp.flexGrow = 2; view.setLayoutParams(lp);
FlexboxLayoutManager (within RecyclerView)
第二种方式是 FlexboxLayoutManager
可以使用在 RecyclerView
的内部.
RecyclerView recyclerView = (RecyclerView) context.findViewById(R.id.recyclerview); FlexboxLayoutManager layoutManager = new FlexboxLayoutManager(context); layoutManager.setFlexDirection(FlexDirection.COLUMN); layoutManager.setJustifyContent(JustifyContent.FLEX_END); recyclerView.setLayoutManager(layoutManager);
或者通过孩子的属性的 FlexboxLayoutManager
你可以这样做:
mImageView.setImageDrawable(drawable); ViewGroup.LayoutParams lp = mImageView.getLayoutParams(); if (lp instanceof FlexboxLayoutManager.LayoutParams) { FlexboxLayoutManager.LayoutParams flexboxLp = (FlexboxLayoutManager.LayoutParams) lp; flexboxLp.setFlexGrow(1.0f); flexboxLp.setAlignSelf(AlignSelf.FLEX_END); }
使用FlexboxLayoutManager
的优点是它可以回收从屏幕上消失的views,为了重用那些出现在用户滚动条上的视图而不是每次都inflate每个单独的view,
这样做可以消耗小得多的内存特别是当Flexbox容器包含了item的总数是很大的时候。
由于RecyclerView
的一些特征,有些FlexBox的属性不可用或者没有实现在FlexboxLayoutManager
。
下面是两个实现之间的属性/特性比较的快速概述
Attribute / Feature | FlexboxLayout | FlexboxLayoutManager (RecyclerView) |
---|---|---|
flexDirection | ||
flexWrap | (except wrap_reverse ) | |
justifyContent | ||
alignItems | ||
alignContent | - | |
layout_order | - | |
layout_flexGrow | ||
layout_flexShrink | ||
layout_alignSelf | ||
layout_flexBasisPercent | ||
layout_(min/max)Width | ||
layout_(min/max)Height | ||
layout_wrapBefore | ||
Divider | ||
View recycling | - | |
Scrolling | *1 |
*1 部分可能用ScrollView
来包装,但是它不太可能用作与一个大集合布局内部的视图,因为它不考虑到视图的回收
Attributes for the FlexboxLayout:
flexDirection
- 这个属性决定了主轴的方向(交叉轴,垂直于主轴。子items根据方向放置到Flexbox布局中
可能的值有: - row (default)
- row_reverse
- column
- column_reverse
- 这个属性决定了主轴的方向(交叉轴,垂直于主轴。子items根据方向放置到Flexbox布局中
flexWrap
- 这个属性控制flex container 是单行或者多行,和交叉轴的方向,可能的值有:
- nowrap (default)
- wrap
- wrap_reverse
justifyContent
- 这个属性控制主轴的对齐方式,可能的值有:
- flex_start (default)
- flex_end
- center
- space_between
- space_around
alignItems
- 这个属性控制交叉轴的对齐方式,可能的值:
- stretch (default)
- flex_start
- flex_end
- center
- baseline
alignContent
- 这个值控制flex的lines对齐方式在fiex容器中(只有多行的时候有效),可能的值:
- stretch (default)
- flex_start
- flex_end
- center
- space_between
- space_around
showDividerHorizontal (one or more of
none | beginning | middle | end
)dividerDrawableHorizontal (reference to a drawable)
*在flex线之间放置水平分隔物 (or flex items when flexDirection
is set tocolumn
orcolumn_rebase
).showDividerVertical (one or more of
none | beginning | middle | end
)dividerDrawableVertical (reference to a drawable)
- 在flex项目之间放置垂直分隔物 (or flex lines when flexDirection
is set tocolumn
orcolumn_rebase
).
- 在flex项目之间放置垂直分隔物 (or flex lines when flexDirection
showDivider (one or more of
none | beginning | middle | end
)dividerDrawable (reference to a drawable)
- 同时设置水平和垂直的分割线。注意,如果与其他属性一起使用
(such asjustifyContent="space_around"
oralignContent="space_between"
… etc) 将
在flex线或flex项目之间的空间,您可能会看到意想不到的空间。请避免使用这些
在同一时间。
同时放置水平和垂直分割线的例子。
res/drawable/divider.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <size android:width="8dp" android:height="12dp" /> <solid android:color="#44A444" /> </shape>
res/layout/content_main.xml
<com.google.android.flexbox.FlexboxLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" app:alignContent="flex_start" app:alignItems="flex_start" app:flexWrap="wrap" app:showDivider="beginning|middle" app:dividerDrawable="@drawable/divider" > <TextView style="@style/FlexItem" android:layout_width="220dp" android:layout_height="80dp" android:text="1" /> <TextView style="@style/FlexItem" android:layout_width="120dp" android:layout_height="80dp" android:text="2" /> <TextView style="@style/FlexItem" android:layout_width="160dp" android:layout_height="80dp" android:text="3" /> <TextView style="@style/FlexItem" android:layout_width="80dp" android:layout_height="80dp" android:text="4" /> <TextView style="@style/FlexItem" android:layout_width="100dp" android:layout_height="80dp" android:text="5" />
- 同时设置水平和垂直的分割线。注意,如果与其他属性一起使用
layout_order (integer)
- 这个属性能改变子views布局的顺序,默认子view显示放置相同的顺序跟他们在XML声明的一样。
layout_flexGrow (float)
- 这个属性决定了子view将增大多少,如果可分配的空间还有多余时根据相对于其他的flex的同一行的items,
如果一个flex的item 有一个正数layout_flexGrow
的值,在flex行中这个item将占据剩余的部分。如果相同
的flex一行有多个flex items有layout_flexGrow
正数的值,剩下的自由的空间分配根据他们声明的layout_flexGrow
值得比例。(类似LinearLayout
的layout_weight
属性)如果不指定,这个值默认设置为0
- 这个属性决定了子view将增大多少,如果可分配的空间还有多余时根据相对于其他的flex的同一行的items,
layout_flexShrink (float)
- 这个属性决定了子view将缩小多少,如果可分配的空间不足时的时候相对于其他的flex的同一行的items.
如果没有指定,默认值设置为1
- 这个属性决定了子view将缩小多少,如果可分配的空间不足时的时候相对于其他的flex的同一行的items.
layout_alignSelf
- 这个属性决定了交叉轴(垂直于主轴)的对齐方式。在同方向对齐可以根据父的
alignItems
决定,但是如果这个属性设置了
其他的属性除了auto
,交叉轴的对齐将会被子view重写,可能的值: - auto (default)
- flex_start
- flex_end
- center
- baseline
- stretch
- 这个属性决定了交叉轴(垂直于主轴)的对齐方式。在同方向对齐可以根据父的
layout_flexBasisPercent (fraction)
- 初始的flex的item长度用一个分数的格式相对于他的父长度,这个子view的初始主要大小尝试扩展根据指定的分数相对于父的
主要大小。
如果这个值设置了,从layout_width
(或者layout_height
)指定的长度会被重写通过这个分数计算的到的值。
这个属性仅当父的长度明确时才有效(MeasureSpec mode isMeasureSpec.EXACTLY
)。默认值是-1
,以为着不设置。
- 初始的flex的item长度用一个分数的格式相对于他的父长度,这个子view的初始主要大小尝试扩展根据指定的分数相对于父的
layout_minWidth / layout_minHeight (dimension)
- 这些属性为FlexboxLayout的孩子设置了最小尺寸限制,一个孩子,不能收缩小于这些属性的值(变化的基础上
flexDirection
属性是指哪个属性将大小限制强加于主轴),不管layout_flexShrink
属性
- 这些属性为FlexboxLayout的孩子设置了最小尺寸限制,一个孩子,不能收缩小于这些属性的值(变化的基础上
layout_maxWidth / layout_maxHeight (dimension)
- 这些属性为FlexboxLayout的孩子设置了最大尺寸限制,一个孩子,不能伸展大于这些属性的值(变化的基础上
flexDirection
属性是指哪个属性将大小限制强加于主轴),不管layout_flexGrow
属性
- 这些属性为FlexboxLayout的孩子设置了最大尺寸限制,一个孩子,不能伸展大于这些属性的值(变化的基础上
layout_wrapBefore (boolean)
- 这个属性强制一个flex线包装,默认值是“false”。也就是说,如果这个被设置为“true”
flex项目,这个项目将成为flex系列的第一个项目。(包装情况不考虑在之前的flex系列中处理的flex项目)
如果“flexwrap”属性设置为“nowrap”,则忽略该属性。在原来的CSS灵活框模块中没有定义等效属性规范,
但是拥有这个属性对于Android开发人员是很有用的。例如,压平在构建网格状布局时的布局,或者是开发人
员想要的情况为了使一个新的flex线与前一个的语义不同,等等。
- 这个属性强制一个flex线包装,默认值是“false”。也就是说,如果这个被设置为“true”
Others
这个库尝试尽可能跟原
Flexible Box specification 功能相同,
但是由于某些原因,比如指定属性的方式在这两者之间是不一样的
CSS和Android XML,与原始规范有一些已知的区别
(1) 没有与 flex-flow
等效的属性
* 因为flex-flow
是设置flex-direction
和flex-wrap
属性的缩写,
从单个属性中指定两个属性在Android中是不实用的。
(2) 没有flex 等效属性
* 同样的,flex
是设置flex-grow
、flex-shrink
和flex-basis
的缩写,
从单个属性中指定这些属性是不实际的。
(3)layout_flexBasisPercent
被引入,而不是
flexBasis
* 本库中的layout_flexBasisPercent
和CSS中的flex-basis
属性都被用于
确定单个flex项目的初始长度。flex-basis
属性接受宽度
诸如1em
、10px
、content
等值,以及诸如此类的百分比值
“10%”和“30%”。layout_flexBasisPercent
只接受百分比值。
但是,指定初始固定宽度值可以通过指定宽度(或高度)值来完成
layout_width(或layout_height,取决于flexDirection
)。同时,相同的
layout_width(或layout_height)中指定”wrap_content”来实现效果。
开发人员想要达到与 ‘content’相同的效果。因此,只有layout_flexBasisPercent
接受百分比值,这不能通过ayout_width(或layout_height)来简单完成
(4) layout_wrapBefore
已经介绍.
* 在CSS灵活的Box模块规范中不存在等价的属性,
但正如上面所解释的,Android开发者将会受益于拥有这个属性
当包装发生时,更多的控制。