android --巧用 flexboxLayout 布局

前言

某天在作项目的时候,遇到了个看似简单但又无从下手的小功能,效果相似微信群聊选择联系人界面: html

在这里插入图片描述
有没有发现选择人员变更后上面部分的展现是从中间往两边扩散的?最开始的时候我是直接用 RecycleView 展现的,就是一再普通不过的九宫格布局了。在产品的要求下要改为相似微信的这种布局,而后我就开始了 “面向搜索引擎”的编程,搜寻了半天,什么仿微信啊,什么中间布局啊(事实证实就算是“面向搜索引擎”的编程,我仍是要学不少,由于,关键字定位的不许确),未果。

而后一想,嘿嘿,没事,轮子没有本身造呗,一看就得自定义布局。遂拿起个人小本本,准备大干一番,用笔写下思路,磨蹭了十几分钟,本子上只有几个立体几何。。。(有个小癖好,写不出来喜欢在本子上画立方体)。前端

而后想一时半会自定义也掌握很差啊,时间又赶,遂又开始了大规模搜索。在快要放弃的时候看到了这篇文章:Android 弹性布局 FlexboxLayout了解一下 看到其中这张图的时候,两眼放光,异常激动啊。 react

图片来自连接博客
看完是否是感受但愿就在前方? 因而看了下 flexboxLayout 的介绍,完彻底全就是前端的 flexbox 布局啊,连属性名称都同样。由于有点 react native 基础,因此事情变得 so easy。最后看到居然支持 RecycleView,只需改动极少许的代码,简直不能太赞。

嗯,废话那么多,铺垫那么长,下面来介绍一下今天的主角 : flexboxLayout 。android

首先要作的事情固然是在项目中集成了:git

compile 'com.google.android:flexbox:1.0.0'
复制代码

1.什么是 flexboxLayout 布局?

github.com/google/flex… 项目简介中是这样一句话来归纳 flexboxLayout 的:github

FlexboxLayout is a library project which brings the similar capabilities of CSS Flexible Box Layout Module to Android. FlexboxLayout 是一个在 Android 上实现 CSS 的 弹性盒状布局 模块的库编程

有前端基础的同窗估计都知道 CSS 中这个布局,用来为盒状模型提供最大的灵活性。由于 android 中这个库属性和 CSS 中 都同样,而且阮一峰老师写的前端知识真的很通俗易懂,因此这里的介绍大多来自 Flex 布局教程segmentfault

在这里插入图片描述
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的全部子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。这里与 react native 相反,与前端 CSS 保持一致。bash

主轴的开始位置(与边框的交叉点)叫作main start,结束位置叫作main end;交叉轴的开始位置叫作cross start,结束位置叫作cross end微信

项目默认沿主轴排列。单个项目占据的主轴空间叫作 main size,占据的交叉轴空间叫作 cross size。

2.容器的属性 (FlexboxLayout 属性介绍)

这里说的容器也就是上面的采用了 Flex 布局的元素,在 android 中也就是引用了 FlexboxLayout 的 控件。即 FlexboxLayout 控件支持的属性。主要属性有:

在这里插入图片描述
各个属性的详细含义这里就再也不赘述,阮一峰老师 这篇文章 写的超级棒,图文并茂,很容易理解,推荐你们看一下。

3.项目的属性 (子 View 属性介绍)

设置被 FlexboxLayout 包裹的子 View 的属性,由于 android 中的 flexboxLayout 布局 和 CSS 中 flex 布局关于子 View 属性有些差别,因此这里详细说明下,取值以下:

  • layout_order (integer)
  • layout_flexGrow (float)
  • layout_flexGrow (float)
  • layout_alignSelf
  • layout_flexBasisPercent (fraction)
  • layout_minWidth / layout_minHeight (dimension)
  • layout_maxWidth / layout_maxHeight (dimension)
  • layout_wrapBefore (boolean)

下面来看一下github文档中对这些属性的描述

3.1 layout_order

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

在这里插入图片描述
看下文档中的这张图,能够看到将 “2” 号 View 的 layout_order 属性设置为 -1时,因为其余的 View 默认都是 1,因此 “2” 号 view会排在最前面,同理,将 “2” 号 View 的 layout_order 的属性值设为 2 时,比其余默认值 1 都大,因此会排在最后。

3.2 layout_flexGrow

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

3.3 layout_flexShrink

该属性定义了子 View 的缩小比例,默认为 1,即若是空间不足,该子 View 将缩小。 若是全部子 View 的 layout_flexShrink 属性都为 1,当空间不足时,都将等比例缩小。若是一个项目的 layout_flexShrink 属性为0,其余子View都为 1,则空间不足时,layout_flexShrink 属性为 0 的不缩小。

在这里插入图片描述
看一下文档中的这张图,开始设置全部子 view 的 layout_flexShrink 属性为1,添加子 view 的时候全部子 view 等比缩小,可是若是设置 layout_flexShrink 属性值为 0,子 view 将会按照原有比例显示,不缩小。

3.4 layout_alignSelf

layout_alignSelf 属性容许单个子 View 有与其余 View 不同的对齐方式,可覆盖 align-items 属性。默认值为 auto,表示继承父元素的 align-items 属性,若是没有父元素,则等同于 stretch。 该属性可能取 6 个值,除了 auto,其余都与 align-items 属性彻底一致

3.5 layout_flexBasisPercent

flex-layout_flexBasisPercent 属性定义了在分配多余空间以前,子 View 占据的主轴空间(main size)。根据这个属性来计算主轴是否有多余空间。它的默认值为 -1,即不设置,采用子 View 的原本大小。

若是设置了这个值,layout_width (或 layout_height )中指定的长度将被该属性的计算值覆盖。这个属性只有在父 View 的长度是肯定的时候才有效(测量模式是 MeasureSpec.EXACTLY 模式下)。 而且该属性值只接受百分比值。

在这里插入图片描述
能够分析下文档中的这张图:能够看到,若是把中间子 View 的这个属性值设为 50% 或 90%,那么这个 View 将占据主轴 50% 或 90% 的空间,而后剩余 View 会看有没有剩余空间换行。若是设置为 -1 默认值,那么将占据给定的大小。

3.6 layout_minWidth / layout_minHeight

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

3.7 layout_maxWidth / layout_maxHeight

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

3.8 layout_wrapBefore

这个属性使得子 View 能够强制换行,无论在 main size 剩余空间有多少。这种对于相似 grid 网格布局中特殊设置某一个 item 布局特别有用。 这个属性是 CSS 中没有的属性。该属性在 flex_wrap 属性值 为 nowrap(不换行)的时候是无效的。 该属性结束 boolean 变量,默认 false,即不强制换行

在这里插入图片描述
分析下文档中的这张图,“5” 号和 “6” 号 View 设置 layout_wrapBefore 属性为ture 的时候,无论前面剩余多少空间,都会强制换行

到这里,flexboxLayout 基本属性就介绍完毕了。

而后再来介绍一下跟 recycleView 结合使用。

4. 高能:与 RecyclewView 结合使用

Flexbox 可以做为一个 LayoutManager(FlexboxlayoutManager) 用在 RecyclerView 里面,这也就意味着你能够在一个有大量 Item 的可滚动容器里面使用 Flexbox,提升性能。具体使用示例:

//设置主轴方向为横轴
        FlexboxLayoutManager manager = new FlexboxLayoutManager(this, FlexDirection.ROW);
        //设置item沿主轴方向的位置
        manager.setJustifyContent(JustifyContent.CENTER);
        //设置item 沿次轴方向的位置
        manager.setAlignItems(AlignItems.CENTER);

        recycleView.setLayoutManager(manager);
        centerGridAdapter = new CenterGridAdapter(items, this);
        recycleView.setAdapter(centerGridAdapter);
复制代码

能够看到跟 RecycleView 的其余 manager 使用同样,只需设置 manager 属性便可,属性值为上面叙述的几个容器的属性。 若是想对某个 item 进行单独的设置,能够在 adapter 中去设置,设置示例代码为:

ViewGroup.LayoutParams lp =  holder.itemLL.getLayoutParams();
        if (lp instanceof FlexboxLayoutManager.LayoutParams) {
            FlexboxLayoutManager.LayoutParams flexboxLp =
                    (FlexboxLayoutManager.LayoutParams)  holder.itemLL.getLayoutParams();
            flexboxLp.setFlexGrow(1.0f);
        }
复制代码

我这里是设置每一个 item 有个权重(至关于 Linearlayout 的 weight 属性),因此会按比例分配 item 的宽,而不是我布局中设定的固定宽高。看下效果:

在这里插入图片描述

是否是有种键盘的感受?而且我只是修改了极少的代码就实现了这个功能。

小试牛刀1

最后,看了那么多,回到最开始的问题上,如今知道相似微信的那个中间扩展的网格布局怎么写的吗? 首先咱们简单分析一下,

  • 主轴方向咱们应该设置为水平方向,即默认 flexDirection :“row”’
  • 能够换行,即 flexWrap:“wrap”
  • 子 View 在主轴方向的对其方式为居中(这一步实现从中间往两边展开),即 justifyContent: "center"
  • 子 View 在交叉轴方向的对其方式为居中,即 alignItems:"center"
  • 子 View 宽高固定

也就是上面讲 Recycleview 结合的例子中去掉单独设置 item 的部分,而且 item 的宽高要根据屏幕来适配的。 嗯,就是 so easy。

小试牛刀2

在这里插入图片描述
实际应用中还有种很常见的就是那种分类选择的布局,像图中的网易和简书中,这种布局用咱们今天的这个主角是否是垂手可得的就实现了?都不用设置特别的属性,内容超过一行自动换行。 代码以下:

//设置主轴方向为横轴
        FlexboxLayoutManager manager = new FlexboxLayoutManager(this, FlexDirection.ROW);
        //设置item沿主轴方向的位置
        manager.setJustifyContent(JustifyContent.FLEX_START);
        //设置item 沿次轴方向的位置
        manager.setAlignItems(AlignItems.CENTER);

        recycleView.setLayoutManager(manager);
        labelAdapter = new LabelAdapter(labels,this);
        recycleView.setAdapter(labelAdapter);
复制代码

总结

因此说了这么多,那么咱们何时会用到这种布局呢?我目前想到的场景主要有 3 类:

  1. 相似LinearLayout 线性布局,可是又能够自动换行的
  2. 相似grid 网格布局的,但总有一两个item的排列方式很特立独行的
  3. 相似瀑布流的,但也是总有一两个item跟别人不同的

固然这些场景加上 RecycleView 就会更加畅享丝滑了。

demo 传送门

参考

阮一峰:Flex 布局教程:语法篇 flexbox-layout 的 github 地址

相关文章
相关标签/搜索