FlexboxLayout的使用说明书

FlexboxLayout的使用说明书

概念

google开源的一套解决复查布局的控件,可以替换Anddroid里的LinearLayout+RelativeLayout,
最重要差异在于 FlexboxLayout 具有 “换行” 的特性,可便捷的写出流式布局,功能类似于CSS中的Flexbox。

场景



以上这种场景,以前一般都会使用ListView或RecycleView或者第三方自动换行控件+ Adapter去实现,实现的代码量稍微有点大。
而现在有了这个FlexboxLayout,实现起来特别简单,代码量也大大的减少了很多,下面看看FlexboxLayout如实实现以上场景

使用

安装配置
bulid.gradle文件(module)

dependencies {   
    compile 'com.google.android:flexbox:0.2.6'
 }

实现

xml实现

<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content"
    app:flexDirection="row"
    app:justifyContent="space_around"
    app:flexWrap="wrap">
    <TextView
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="吃货"
        android:layout_marginBottom="10dp"/>
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="逗比" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="创业者" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="上班这点事" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="影视天堂" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="大学生活" />
    <TextView
        android:padding="6dp"
        android:layout_marginBottom="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="单身狗" />
    <TextView
        android:padding="6dp"
        android:layout_marginBottom="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="运动和健身" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="网购达人" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="旅游" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="程序员" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="追星族" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="短片小说" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="美食" />
    <TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="教育" />
<TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="学生党" />
<TextView
        android:layout_marginBottom="10dp"
        android:padding="6dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/shape_text"
        android:text="汪星人" />
</com.google.android.flexbox.FlexboxLayout>

即把所有子控件写到最外层是FlexboxLayout的里面即可

效果:



代码实现

public class CodeActivity extends AppCompatActivity {

    String[] tags = {"吃货", "逗比", "创业者", "上班这点事儿",
            "影视天堂", "大学生活", "单身狗", "运动和健身",
            "网购达人", "旅游", "程序员", "追星族", "短篇小说",
            "美食", "教育", "学生党", "汪星人"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.code_layout);

        FlexboxLayout flexboxLayout = 
        (FlexboxLayout) findViewById(R.id.flexbox_layout);

        for (int i = 0;i < tags.length;i++) {
            LinearLayout layout = (LinearLayout) LayoutInflater.from(this)
            .inflate(R.layout.textview,null);
            TextView textview = (TextView) layout.findViewById(R.id.textview);
            textview.setText(tags[i]);
            flexboxLayout.addView(layout);
        }

    }

}

效果



属性讲解

接下来,以一个简单的demo来分析FlexboxLayout里经常用到的属性
直接在布局最外层加入,如下:

<?xml version="1.0" encoding="utf-8"?>  
<com.google.android.flexbox.FlexboxLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
    <TextView
          android:text="textview1"
          android:id="@+id/textview1"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"/>
   <TextView
          android:text="textview2"
          android:id="@+id/textview2"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"/>
    <TextView
          android:text="textview3"
           android:id="@+id/textview3"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
      />
</com.google.android.flexbox.FlexboxLayout>

咱们先看下没有添加额外属性(FlexboxLayout的属性)的效果



跟LinearLayout一样,默认是水平方向的

flexDirection(方向属性)

类似 LinearLayout 的 vertical 和 horizontal

值说明备注row默认值,主轴为水平方向,起点在左端

row-reverse主轴为水平方向,起点在右端

column主轴为垂直方向,起点在上沿

column-reverse主轴为垂直方向,起点在下沿







flexWrap(换行属性)

默认情况下 Flex 跟 LinearLayout 一样,都是不带换行排列的,但是flexWrap属性可以支持换行排列

值说明备注nowrap不换行

wrap按正常方向换行

wrap-reverse按反方向换行

我们把上面的demo加上该属性试试,首先我们先把水平方向填满



然后分别加上flexWrap属性,值为wrap,wrap-reverse





发现两个都换行了,而且reverse的时候,是最后添加的text3在最上面

justifyContent

值说明备注flex-start默认值,左对齐

flex-end右对齐

center居中

space-between两端对齐,项目之间的间隔都相等

space-around每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍











可以看到前三个属性类似gravity,而后两个类似于LinearLayout里的weight属性

alignContent

属性定义项目在交叉轴上如何对齐

值说明备注flex-start交叉轴的起点对齐

flex-end交叉轴的终点对齐

center交叉轴的中点对齐

baseline项目的第一行文字的基线对齐

stretch默认值,如果项目未设置高度或设为auto,将占满整个容器的高度

这里解释下什么是主/交叉轴,看图:



图中的副轴即为交叉轴
这个属性什么情况下起作用呢?
当主轴是水平方向时,只有存在多行的情况下,这个属性才起作用,如图:



添加了没有任何效果,现在换成多行试试:





alignItems

与aliginConent属性的区别在于单行的情况下也生效

值说明备注flex-start交叉轴的起点对齐

flex-end交叉轴的终点对齐

center交叉轴的中点对齐

baseline项目的第一行文字的基线对齐

stretch默认值,如果项目未设置高度或设为auto,将占满整个容器的高度



子控件属性

—被包裹在FlexboxLayout布局里控件的属性

layout_order

值说明备注数字这个属性主要用于子控件的,可以控制排列的顺序,负值在前,正值在后,按照从小到大的顺序依次排列

看下添加该属性前后的效果对比图





由效果图可以看到该属性决定这子控件所在的位置顺序的

layout_flexBasisPercent

值说明备注百分数


该属性只有在父布局为MeasureSpec.EXACTLY(
wrap_parent -> MeasureSpec.AT_MOST
match_parent -> MeasureSpec.EXACTLY
具体值 -> MeasureSpec.EXACTLY)时生效,设置三个模式看下效果

wrap_parent(没有效果)



match_parent(有效果)



指定值(有效果)



可以看到当父布局为match或者固定值时,子控件设置的该属性会起作用(占屏幕的50%)

layout_wrapBefore

值说明备注true/falseitem是否在 flex line 的第一个,默认为 false,在父布局app:flexWrap=”nowrap”时不起作用

item 是否在 flex line 的第一个,默认为 false,
在父布局app:flexWrap=”nowrap”时不起作用
对比下设置的效果





总结

优点:

  • 具有LinearLayout的功能,除了能自动换行外,还具有LinearLayout与RelativeLayout没有的一些属性

缺点:

  • 不具有RelativeLayout的一些属性,比如layout_alignParentBottom=”true”
  • 从过度绘制与帧率上看,与LinearLayout/RelativeLayout没有多大区别,有兴趣的同学可以写一个复杂的界面对比下。

适用场景

  • 自动换行
  • 流式布局(子布局方向一致的)

问题

FlexboxLayout的targetSdkVersion=25

参考

github.com/google/flexb

编辑于 2017-09-08 14:34