之前看到一個很炫酷的布局:FlexboxLayout,可以很方便地實現瀑布流的效果。今天正好用到項目中,對FlexboxLayout進行一個簡單的學習。

一、效果圖

先來看一波效果圖。


很熟悉,對不對?就是簡書的定製熱門頁面。通過今天的學習,利用FlexboxLayout+RecyclerView就可以實現。

下面是自己實現的效果圖:



像上述的應用場景,會經常在一些APP中看到。那麼就學起來吧,看看是怎麼實現的。

二、FlexboxLayout簡介

FlexboxLayout is a library project which brings the similar capabilities of CSS Flexible Box Layout Module to Android.

FlexboxLayout是一個Android平台上與CSS的 Flexible box 布局模塊 有相似功能的庫。Flexbox 是CSS 的一種布局方案,可以簡單、快捷的實現複雜布局。FlexboxLayout可以理解成一個高級版的LinearLayout,因為兩個布局都把子view按順序排列。兩者之間最大的差別在於FlexboxLayout具有換行的特性。

FlexboxLayout是Google開源的一款強大的布局,如果英文好可以直接看其屬性信息的詳細介紹,Github地址

當然,也可以看一些翻譯過來的對FlexboxLayout的介紹,比如:Android可伸縮布局-FlexboxLayout(支持RecyclerView集成),介紹的很清楚。

三、FlexboxLayout重要屬性

下面僅介紹幾中常用的FlexboxLayout屬性。

flexDirection:

flexDirection屬性決定了主軸的方向,即FlexboxLayout裡子Item的排列方向,有以下四種取值:

row (default): 默認值,主軸為水平方向,從左到右。
row_reverse:主軸為水平方向,起點在有端,從右到左。
column:主軸為豎直方向,起點在上端,從上到下。
column_reverse:主軸為豎直方向,起點在下端,從下往上。


flexWrap

flexWrap 這個屬性決定Flex 容器是單行還是多行,並且決定副軸(與主軸垂直的軸)的方向。可能有以下3個值:

noWrap: 不換行,一行显示完子元素。
wrap: 按正常方向換行。
wrap_reverse: 按反方向換行。


justifyContent

justifyContent 屬性控制元素主軸方向上的對齊方式,有以下5種取值:

flex_start (default): 默認值,左對齊
flex_end: 右對齊
center: 居中對齊
space_between: 兩端對齊,中間間隔相同
space_around: 每個元素到兩側的距離相等。


alignItems

alignItems 屬性控制元素在副軸方向的對齊方式,有以下5種取值:

stretch (default) :默認值,如果item沒有設置高度,則充滿容器高度。
flex_start:頂端對齊
flex_end:底部對齊
center:居中對齊
baseline:第一行內容的的基線對齊


alignContent

alignContent 屬性控制多根軸線的對齊方式(也就是控制多行,如果子元素只有一行,則不起作用),可能有以下6種取值:

stretch (default): 默認值,充滿交叉軸的高度(測試發現,需要alignItems 的值也為stretch 才有效)。
flex_start: 與交叉軸起點對齊。
flex_end: 與交叉軸終點對齊。
center: 與交叉軸居中對齊。
space_between: 交叉軸兩端對齊,中間間隔相等。
space_around: 到交叉軸兩端的距離相等。


FleboxLayout子元素支持的重要屬性

以下介紹幾個子元素支持的重要屬性

layout_flexGrow(float)

layout_flexGrow 子元素的放大比例, 決定如何分配剩餘空間(如果存在剩餘空間的話),默認值為0,不會分配剩餘空間,如果有一個item的 layout_flexGrow 是一個正值,那麼會將全部剩餘空間分配給這個Item,如果有多個Item這個屬性都為正值,那麼剩餘空間的分配按照layout_flexGrow定義的比例(有點像LinearLayout的layout_weight屬性)。

layout_flexBasisPercent (fraction)

layout_flexBasisPercent的值為一個百分比,表示設置子元素的長度為它父容器長度的百分比,如果設置了這個值,那麼通過這個屬性計算的值將會覆蓋layout_width或者layout_height的值。但是需要注意,這個值只有設置了父容器的長度時才有效(也就是MeasureSpec mode 是 MeasureSpec.EXACTLY)。默認值時-1。

FlexboxLayout還有需要其他的擁有強大功能的屬性,如有需要,可通過上面兩篇文章進行了解。

四、FlexboxLayout使用

1、添加依賴

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

2、具體代碼

第一種方式:
布局文件
<?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="match_parent"
    android:id="@+id/flexbox_layout"
    app:flexWrap="wrap"
    app:alignItems="center"
    app:alignContent="flex_start"
    app:flexDirection="row"
    app:justifyContent="flex_start"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        app:layout_alignSelf="flex_start"
        android:text="程序員"
        android:gravity="center"
        android:textColor="@color/text_color"
        />
  ..............................................................................
</com.google.android.flexbox.FlexboxLayout>

可以通過向FlexboxLayout添加多個子控件來實現瀑布流的效果。也可以在代碼中動態添加子控件來實現同種效果。不過這種情況不適合子View過多的場景,如果子View過多,建議使用FlexboxLayout+RecyclerView的方式,下面具體介紹。

第二種方式:

首先要換掉原來的依賴,依賴最新的alpha版本,如下:

 compile 'com.google.android:flexbox:0.3.0-alpha2'
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="false"
                android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/background_material_light_1"
        android:fitsSystemWindows="true">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/iv_wrong"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentLeft="true"
                android:src="@drawable/favor_wrong"/>

            <ImageView
                android:id="@+id/iv_right"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:paddingRight="10dp"
                android:src="@drawable/favor_right"/>
        </RelativeLayout>


    </android.support.v7.widget.Toolbar>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_favor"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/toolbar">
    </android.support.v7.widget.RecyclerView>
</RelativeLayout>

主布局中放入RecyclerView。

添加內容
 mAdapter = new FavorMovieAdapter(list,mContext,mSelectList);
        FlexboxLayoutManager manager = new FlexboxLayoutManager();
        //設置主軸排列方式
        manager.setFlexDirection(FlexDirection.ROW);
        //設置是否換行
        manager.setFlexWrap(FlexWrap.WRAP);
        mRvFavor.setLayoutManager(manager);
        mRvFavor.setItemAnimator(new DefaultItemAnimator());
        mRvFavor.setAdapter(mAdapter);

通過FlexboxLayoutManager 作為一個LayoutManager(FlexboxlayoutManager) 用在RecyclerView裏面,實現FlexboxLayout的強大功能。

在Adapter設置子元素屬性

填充每一行的剩餘空間

ViewGroup.LayoutParams params = holder.mTitle.getLayoutParams();
        if (params instanceof FlexboxLayoutManager.LayoutParams) {
            FlexboxLayoutManager.LayoutParams flexboxLp = (FlexboxLayoutManager.LayoutParams) holder.mTitle.getLayoutParams();
            flexboxLp.setFlexGrow(1.0f);
        }

五、總結

FlexboxLayout+RecyclerView可以實現瀑布流的效果,不需要指定列數,可以實現自動換行,而且FlexboxLayout具有的各種屬性,使得瀑布流的形式更加靈活多變。以上只是一些簡單的使用。


分享