Android开发弹性布局FlexboxLayout知识总结

今天分享一下弹性布局FlexboxLayout的使用总结,又是一篇个人有道云笔记转移系列。早些年我们实现一个换行的标签云、实现一个不规则的九宫格、实现一个不规整瀑布流等等这些“嘿嘿嘿”设计总是要思索半天,FlexboxLayout的出现面对这些问题将为你节省几亿个脑细胞不在话下。我第一次接触这个布局方式还是从早前一个前端写H5的小哥嘴里得到的,我顺便举一反三搜了一下发现我们Android上也有,还是google官方出品,看来知识都是相通的。好了,废话不多说,直接淦!

GitHub

官方地址: https://github.com/google/flexbox-layout

接入依赖:

dependencies {
    implementation 'com.google.android:flexbox:2.0.1'
}

值得注意的是从1.1.0开始,该库直接对接AndroidX,如果想要使用1.1.0及以上版本尽快升级到AndroidX咯。

简单使用方式

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>

From Code

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.setOrder(-1);
lp.setFlexGrow(2);
view.setLayoutParams(lp);

FlexboxLayoutManager (within RecyclerView)

// 针对所有item
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);

// 针对单个item
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);
}

相关属性

FlexboxLayout相关属性

下边我直接介绍相关属性使用方法

父布局属性

以下五种是父布局中所使用的,也是最常用的。

flexDirection

flexDirection属性是决定主轴的方向。好比LinearLayout的vertical(垂直) 和 horizontal(水平)方向。

  • row:一般为默认值,主轴为水平方向,起点在左端。
  • row-reverse: 主轴为水平方向,起点在右端。
  • column:主轴为垂直方向,起点在上沿。
  • column-reverse:主轴为垂直方向,起点在下沿。

flexWrap

flexWrap属性是决定是否换行排列,默认情况下是不支持换行排列。

  • nowrap:不换行。
  • wrap: 正常方向换行。
  • wrap-reverse: 反方向换行。

justifyContent

justifyContent指定了项目在主轴上的对齐方式。

  • flex-start: 默认值为左对齐。
  • flex-end: 右对齐。
  • center: 居中。
  • space-between: 两端对齐,其间间距相等。
  • space-around: 两侧间距相等。

justifyContent图示

alignltems

alignltems指定项目在副轴(交叉轴,和主轴垂直)上的对齐方式。

  • flex-start: 交叉轴的起点对齐。(上)
  • flex-end: 交叉轴的终点对齐。(下)
  • center: 交叉轴的中点对齐。(中间线)
  • baseline: 第一行文字的基线对齐。()
  • stretch: 默认值是占满整个容器的高度,在未设置高度或者为auto。

alignltems图示

alignContent

alignContent指定多根轴线的对齐方式,如果只有一条轴,该属性不起任何作用。

  • flex-start: 与交叉轴的起点对齐。
  • flex-end: 与交叉轴的终点对齐。
  • center: 与交叉轴的中点对齐。
  • space-between: 与交叉轴的两端对齐,轴线之间的间隔分布均匀。
  • space-around: 每根轴线两侧的间隔相等。
  • stretch: 默认值为轴线占满整个交叉轴。

alignContent图示

分割线

水平分割线

采用showDividerHorizontaldividerDrawableHorizontal属性设置水平分割线

  • showDividerHorizontal
    控制显示水平方向的分割线,值为none | beginning | middle | end其中的一个或者多个。
  • dividerDrawableHorizontal
    设置Flex 轴线之间水平方向的分割线。

垂直分割线

采用showDividerVerticaldividerDrawableVertical属性设置垂直分割线

  • showDividerVertical
    控制显示垂直方向的分割线,值为none | beginning | middle | end其中的一个或者多个。
  • dividerDrawableVertical
    设置子元素垂直方向的分割线。

水平垂直分割线

采用showDividerdividerDrawable属性同时设置水平垂直分割线

  • showDivider
    控制显示水平和垂直方向的分割线,值为none | beginning | middle | end其中的一个或者多个。
  • dividerDrawable
    设置水平和垂直方向的分割线,但是注意,如果同时和其他属性使用,比如为Flex轴、子元素设置了justifyContent=“space_around”alignContent=“space_between” 等等。可能会看到意料不到的结果,因此应该避免和这些值同时使用。

子布局属性

layout_order

这个属性可以改变布局子视图的顺序。默认情况下,子元素的显示和布局顺序与布局XML中的顺序相同。如果没有指定,则将1设置为默认值( CSS 中默认值为 0) ,数值越小,排列越靠前。

layout_flexGrow

放大比例。这个属性类似于 LinearLayout 中的 layout_weight 属性,如果没有指定,则将 0 设置为默认值。如果果同一 flex 行中的多个子 View 有正的 layout_flexGrow 值,那么剩余的空闲空间将根据它们声明的 layout_flexGrow 值的比例分布。

<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="300dp"
    android:layout_height="300dp"
    android:background="@android:color/black">

    <!--
         flex-grow(放大比例,剩余空间怎么分配) : 权重
         float FLEX_GROW_DEFAULT = 0f;

         剩余宽度 = 300 - (0 +  0 + 0) = 300
         tv1宽度 = 0 + 300 * (2 / 4) = 150
         tv2宽度 = 0 + 300 * (1 / 4) = 75
         tv3宽度 = 0 + 300 * (1 / 4) = 75
    -->

    <TextView
        android:id="@+id/tv1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_purple"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv1"
        android:textColor="@android:color/white"
        app:layout_flexGrow="2" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#FFC107"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv2"
        app:layout_flexGrow="1" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#00BCD4"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv3"
        app:layout_flexGrow="1" />

</com.google.android.flexbox.FlexboxLayout>

layout_flexShrink

缩小比例。如果所有子 View 的 layout_flexShrink 属性都为 1,当空间不足时,都将等比例缩小。如果一个项目的 layout_flexShrink 属性为0,其他子View都为 1,则空间不足时,layout_flexShrink 属性为 0 的不缩小。

<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="300dp"
    android:layout_height="500dp"
    android:background="@android:color/black">

    <!--
        flex-shrink (缩小比例,超出空间怎么压缩)
        默认: float FLEX_SHRINK_DEFAULT = 1f;

        计算方法:
        孩子宽度和 = 150 * 3 = 450
        450 - 300 = 150 即超出父布局宽度150
        tv1最终宽度 = 自身宽度150 - 超出宽度所占比例的宽度150 * (2 / 4)  = 75
        tv2最终宽度 = 自身宽度150 - 超出宽度所占比例的宽度150 * (1 / 4)  = 112.5
        tv3最终宽度 = 自身宽度150 - 超出宽度所占比例的宽度150 * (1 / 4)  = 112.5
    -->

    <TextView
        android:id="@+id/tv1"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_purple"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv1"
        android:textColor="@android:color/white"
        app:layout_flexShrink="2" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:background="#FFC107"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv2"
        app:layout_flexShrink="1" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:background="#00BCD4"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv3"
        app:layout_flexShrink="1" />

</com.google.android.flexbox.FlexboxLayout>

layout_alignSelf

子元素对齐。对齐方式,取值和align相同,覆盖align-items。

layout_alignSelf 属性可以给子元素设置对齐方式,这个属性的功能和alignItems一样,

只不过alignItems作用于所有子元素,而 layout_alignSelf 作用于单个子元素。

默认值为auto, 表示继承alignItems属性,如果为auto以外的值,则会覆盖alignItems属性。有以下6种取值:

  • auto (default)
  • flex_start
  • flex_end
  • center
  • baseline
  • stretch

layout_flexBasisPercent

子元素占父元素百分比。layout_flexBasisPercent的值为一个百分比,表示设置子元素的长度为它父容器长度的百分比,如果设置了这个值,那么通过这个属性计算的值将会覆盖layout_width或者layout_height的值。

但是需要注意,这个值只有设置了父容器的长度时才有效,默认值是-1。

<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="300dp"
    android:layout_height="300dp"
    android:background="@android:color/black">

    <!--
        layout_flexBasisPercent 
        决定了在分配多余空间之前,子元素占据的主轴空间的百分比。
        默认为自身大小     
    -->

    <TextView
        android:id="@+id/tv1"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_purple"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv1"
        android:textColor="@android:color/white"
        app:layout_flexBasisPercent="40%" />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:background="#FFC107"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv2"
        app:layout_flexBasisPercent="30%" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:background="#00BCD4"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv3"
        app:layout_flexBasisPercent="20%" />

</com.google.android.flexbox.FlexboxLayout>

layout_minWidth / layout_minHeight

这个属性设置了子 View 的最小的宽和高。在 layout_flexShrink 模式下,再怎么缩小也不会小于这个值

layout_maxWidth / layout_maxHeight

这个属性设置了子 View 的最大的宽和高。在 layout_flexGrow 模式下,再怎么放大也不会大于这个值

layout_wrapBefore

这个属性使得子 View 可以强制换行,不管在 main size 剩余空间有多少。这种对于类似 grid 网格布局中特殊设置某一个 item 布局特别有用。默认 false。

最后

我是i猩人,总结不易,转载注明出处,喜欢本篇文章的童鞋欢迎点赞、关注哦。

参考

  • https://github.com/google/flexbox-layout
  • https://stackoverflow.com/questions/31250174/css-flexbox-difference-between-align-items-and-align-content
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值