Google最近开源了一个和CSS3中FlexBox布局功能类似的flexbox-layout,项目地址:google/flexbox-layout ,Google将其引入以提高复杂布局的能力。
FlexBoxLayout可以理解成一种更高级的LinearLayout,不过比LinearLayout更加强大和灵活。如果我们使用LinearLayout布局的话,那么不同的分辨率,也许我们要重新调整布局,势必会需要跟多的布局文件放在不同的资源目录。而使用FlexBoxLayout来布局的话,可以简单、完整、响应式的实现各种页面布局。
具体使用方式在项目地址的介绍文档有讲解,只需要添加一下依赖:
compile 'com.google.android:flexbox:0.2.7'
(1)下面介绍Flexbox的布局和相关名称所代表的意思
上图是官方给出的示例图,其中的概念:
1、flex container:父容器,用来包含子元素,对应于FlexboxLayout类;
2、flex item:子元素,父容器直接包裹的元素;
3、main axis:主轴,子元素通过主轴来排列,如上图是从左往右;
4、corss axis:副轴,垂直于主轴的第二个轴,从上往右;
5、main start和main end:父容器中主轴开始和结束的边界,子元素从main start往main end的方向排列(如果主轴是水平,起点在左端,main start,main end 用来控制子元素从左向右排列);
(2)FlexboxLayout所支持的属性
Container的属性
1、flexDirection: 属性决定主轴(和副轴,垂直于主轴的方向(即项目中子元素的排列方向);
有以下四个值:
row (default):主轴为水平方向,起点在左端;
row_reverse:主轴为水平方向,起点在右端;
column:主轴为垂直方向,起点在上沿;
column_reverse:主轴为垂直方向,起点在下沿;
2、flexWrap:默认情况下FlexboxLayout跟LinearLayout一样,都不带换行排列的,但是flexWrap属性可以支持换行排列。
有以下三个值:
nowrap (default):不换行;
wrap:换行,如下图所示;
wrap_reverse:副轴方向置反,上图倒置一下,具体可以自己运行试验一下;
3、justifyContent:定义了子项在主轴上的对齐方式,控制子项沿主轴对齐。
有以下五个值:
flex_start(默认值):左对齐;
flex_end:右对齐;
center:居中;
space_between:两端对齐,项目之间的间隔都相等;
space_around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
4、alignItems:属性定义子项在副轴轴上如何对齐,控制子项沿副轴对齐(单行起作用)。
有以下五个值:
flex_start:交叉轴的起点对齐;
flex_end:交叉轴的终点对齐;
center:交叉轴的中点对齐;
baseline: 项目的第一行文字的基线对齐;
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度;
5、alignContent:属性定义多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
有以下六个值:
flex_start:与交叉轴的起点对齐;
flex_end:与交叉轴的终点对齐;
center:与交叉轴的中点对齐;
space_between:与交叉轴两端对齐,轴线之间的间隔平均分布;
space_around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍;
stretch(默认值):轴线占满整个交叉轴;
6、showDividerHorizontal / showDividerVertical:控制显示水平 / 垂直方向的分割线,值为none、beginning、middle和end其中的一个或者多个;
7、dividerDrawableHorizontal / dividerDrawableVertical:设置Flex 轴线之间水平方向 / 垂直方向的分割线;
8、showDivider:控制显示水平和垂直方向的分割线,值为none | beginning | middle | end其中的一个或者多个。
9、dividerDrawable:设置水平和垂直方向的分割线,但是注意,如果同时和其他属性使用,比如为 Flex 轴、子元素设置了justifyContent=”space_around” 、alignContent=”space_between” 等等。可能会看到意料不到的空间,因此应该避免和这些值同时使用。
子元素的属性
FlexboxLayout除了上述属性外,还支持如下子元素属性:
1、layout_order: 控制子元素布局的顺序,默认值为1,这种情况下子元素的排列方式按照文档流的顺序依次排序,而order属性可以控制排列的顺序,负值在前,正值在后,按照从小到大的顺序依次排列。
2、layout_flexGrow:类似于LinearLayout中的weight属性一样;
如果所有子项的layout_flexGrow属性都为1,则它们将等分剩余空间(如果有的话),即每个子项占有三分子一。如果一个项目的 layout_flexGrow 属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍;
3、layout_flexShrink:定义了子项的缩小比例,默认为1,即如果空间不足,该子项将缩小,如果为0,则不变化;
如果所有子项的 layout_flexShrink 属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小;
4、layout_alignSelf:允许单个元素有与其它子项不一样的对齐方式,可覆盖alignItems属性,默认值为auto,表示继承父元素的alignItems属性,如果没有父元素,则等同于stretch;
auto (default):继承父元素的alignItems;
flex_start:以下五项和alignItems相同;
flex_end
center
baseline
stretch
5、layout_flexBasisPercent:只能为百分比的值,表示设置子项的长度为它父容器长度的百分比,如果设置了这个值,那么通过这个属性计算的值将会覆盖layout_width或者layout_height的值,但是,只有父容器的MeasureSpec的Mode是MeasureSpec.EXACTLY的模式时才有效,默认值是-1;
6、layout_minWidth / layout_minHeight (dimension):强制限制 FlexboxLayout的子元素(宽或高)不会小于最小值,不管layout_flexShrink这个属性的值为多少,子元素不会被缩小到小于设置的这个最小值;
7、layout_maxWidth / layout_maxHeight (dimension):这个和上面的刚好相反,强制限制FlexboxLayout子元素不会大于这个最大值, 不管layout_flexGrow的值为多少,子元素不会被放大到超过这个最大值;
8、layout_wrapBefore:属性控制强制换行,默认值为false,如果将一个子元素的这个属性设置为true,那么这个子元素将会成为一行的第一个元素。这个属性将忽略flex_wrap 设置的 noWrap值;
(3)与传统CSS弹性布局不同之处
1、没有flex-flow属性 :因为没必要;
2、没有flex属性:同样没必要;
3、layout_flexBasisPercent 替代了flexBasis。如果子元素宽高确定了,可以指定具体值或百分比,如果是包裹内容,那只能是百分比;
4、不能确定min-width和min-height:因为谷歌还没实现;
(4)总结
FlexboxLayout是一个与CSS Flexbox有类似功能的强大布局,具有换行特性,使用起来特别方便,但是,FlexboxLayout是没有考虑View回收的,因此,它只使用于只有少量子Item的场景,如果向其中添加大量Item 是灰导致内存溢出的。所幸,最新的版本添加了与RecyclerView的集成,这就可以在有大量子Item的场景下使用了,只是最新的版本还是alpha版,还没有出稳定的版本,相信不久后就能使用稳定的版本了。另外,FlexboxLayout的这些属性的含义可能不好理解 ,建议大家去写个demo试一下每个属性的每个值看看是什么效果,这样就能很好的理解每个属性了。笔者就是自己模仿着官方给的,自己写了一遍试一试各个属性的效果;
小demo:https://github.com/henryneu/MyFlexboxLayout
参考:
https://github.com/google/flexbox-layout
https://www.oschina.net/news/73442/google-flexbox-layout