百分比布局标签布局之FlexBoxLayout

最近在看google的demo,想逼着自己看源码,所以,今天来看看FlexBoxLayout,起初第一次用Flex布局的时候还是在学习react native的时候(虽然现在都好久没玩过了-_-!),今天把google的demo顺着自己的想法又重新敲了一遍,把玩之后看了下源码,确实是有点复杂啊,每个步骤都要进行各种分类,想想那么多的布局种类,往下看的时候我都差点放弃了(基础不好啊),随后会附上demo,比google demo简单好理解。

布局控制的5大属性

flexDirection

  1. row (default)
  2. row_reverse
  3. column
  4. column_reverse

根据官网给的理解就是这个属性决定了布局主轴的方向。首先来看看gif图

百分比布局标签布局之FlexBoxLayout_第1张图片

从图中就可以看出
row开头的是决定了布局的item沿着横轴进行变化,row是沿着左顶点(left)进行顺序排序,row_reverse沿着右顶点(right)进行反序进行排序

column开头的决定了布局的item沿着纵轴进行变化,column是沿着上顶点(top)进行顺序排序,column_reverse是沿着下顶点(bottom)进行反序排序。

也就是说,flexDirection这个属性决定了items在布局的方向。

flexWrap

  1. nowrap (default)
  2. wrap
  3. wrap_reverse

根据官网意思看,这个属性控制了items们在横轴方向上是单行还是多行。看看gif图

百分比布局标签布局之FlexBoxLayout_第2张图片

这个属性很有意思:
设置nowrap的时候有点像LinearLayout的子view的宽度或高度设置了weight,大家在一行平均分宽度,

设置wrap,那就有点像我们android开发的时候经常会使用到的标签控件啦—流式布局,按控件的宽度一个个排列,大于整体宽度的时候就换行,看源码知道,在onMeasure的时候就已经计算好了一行有多少个item,每一行都是用FlexLine去存储,FlexLine里面存储了这一行有多少个mItemCount,还有left,top,right,bottom等等参数信息。

设置wrap_reverse,将item的设置在布局的底部,然后将每一行进行反转,行内的items不进行排序,按照原来输出,这个行也是很有意思的,根据源码里面所示, List mFlexLines = new ArrayList<>();存储了所有的行,FlexLine存储了每一行中的item的数目,还有item的各种LayoutParame参数,在给flexWrap设置wrap_reverse的时候,他是从底部开始布局,看代码,每一次布局都是从布局底部减去控件的高度来拿到item的top,也就是item放在最后一行,以此类推。

 if (mFlexWrap == FLEX_WRAP_WRAP_REVERSE) {

                  //FlexWrap是FLEX_WRAP_WRAP_REVERSE 并且Direction按Column排列
                    if (isRtl) {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childRight) - child.getMeasuredWidth(),
                                childBottom - child.getMeasuredHeight(), Math.round(childRight),
                                childBottom);
                  //是FLEX_WRAP_WRAP_REVERSE 并且Direction按行ROW排列
                    } else {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childLeft), childBottom - child.getMeasuredHeight(),
                                Math.round(childLeft) + child.getMeasuredWidth(),
                                childBottom);
                    }
                } else {
                //FlexWrap是Wrap或是NoWrap,并且Direction按Column排列
                    if (isRtl) {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childRight) - child.getMeasuredWidth(), childTop,
                                Math.round(childRight), childTop + child.getMeasuredHeight());
                //FlexWrap是Wrap或是NoWrap,并且Direction按ROW排列                
                    } else {
                        layoutSingleChildHorizontal(child, flexLine, mFlexWrap, mAlignItems,
                                Math.round(childLeft), childTop,
                                Math.round(childLeft) + child.getMeasuredWidth(),
                                childTop + child.getMeasuredHeight());
                    }
                }

justifyContent

  1. flex_start (default)
  2. flex_end
  3. center
  4. space_between
  5. space_around

官网的意思是这个属性控制沿着主轴对齐,也就是说,当flexDirection设置ROW的时候,主轴就是行,按行进行对齐,如果flexDirection设置的是Column,主轴就是列,那就按列进行对齐,看gif图


一、当flexDirection设置ROW,主轴是按行的时候

百分比布局标签布局之FlexBoxLayout_第3张图片

从gif中可以看出,当FlexWrap设置为wrap的时候
1. flex_start 就相当于左对齐,
2. flex_end相当于右对齐
3. center相当于居中对齐
4. space_between相当于两端对齐
5. space_around相当于分散对齐
当FlexWrap设置为NoWrap的时候,这个就要分情况了,当布局有剩余部分的时候,跟上面功能一样,当布局已经把剩余空间填满了,那justifyContent就相当于无效了,这个也很好理解,没有空间也就没有对其分配了。

二、当flexDirection设置ROW,主轴是按行的时候

百分比布局标签布局之FlexBoxLayout_第4张图片

和上面主轴为row的情况一样,当FlexWrap设置为NoWrap,并且没有剩余空间的时候,也是不起作用的

alignItems

  1. stretch (default)
  2. flex_start
  3. flex_end
  4. center
  5. baseline

官网介绍,此属性控制沿横轴的对齐方式,意思其实就是如果当前Direction为ROW,比如一行items,可以放在最上面,也可以放在最下面,中间等等。如果Direction为column,items就可以放在最左边、中间、或是右边等等。

这个地方要分两种情况来看待了
下面的gif是Direction设置ROW,FlexWrap设置NoWrap(justifyContent先不看了,上面说了,当FlexWrap设置NoWrap,并且无剩余空间的时候,justifyContent是不起效果的,所以justifyContent就看做默认值为Flex Start,虽然FlexWrap设置为Wrap,justifyContent是可以使用对齐方式的,但是,在对alignItems设置属性的时候,布局几乎是不动的,只有baseline基准线稍微对齐了下,所以,在这个地方设置justifyContent有点矛盾,所以,就把他看做默认值来看吧,当然,如果你设置FlexWrap设置Wrap肯定是可以使用的,因为有了空余空间,justifyContent就能对空余控件进行对齐操作),然后对alignItems进行测试

百分比布局标签布局之FlexBoxLayout_第5张图片
测试结果可以发现FlexWrap设置Wrap的时候,alignItems的属性几乎对布局不起作用,唯一动的就是Baseline基准线动了一下,这也就是我为什么设置justifyContent为默认值的原因了。

结果显示:
1. stretch 有点像weight,填充纵向的剩余部分
2. flex_start 行顶部对齐
3. flex_end 行底部对齐
4. center 行居中对齐
5. baseline 行内的文字进行基准线对齐

Direction设置Column,FlexWrap设置NoWrap,然后对alignItems进行测试就不演示了,和上面一样,只不过是在column方向进行改变,gif就不贴了,大家可以下载下demo把玩,我把结果贴出来
结果显示:
1. stretch 有点像weight,填充横向的剩余部分
2. flex_start 列左部对齐
3. flex_end 列右部对齐
4. center 列居中对齐
5. baseline 无效

alignContent

  1. stretch (default)
  2. flex_start
  3. flex_end
  4. center
  5. space_between
  6. space_around

官网介绍,此属性控制Flex容器中的Flex行的对齐方式

在上面alginItems的介绍中,我们在实践中发现,Direction设置ROW,FlexWrap设置Wrap,justifyContent为默认值,这个控件几乎是不能参与对齐,只有当FlexWrap设置为NoWrap,alginItems才可以进行控制,但是,我现在想去控制布局怎么办呢?这时候alignContent就完成这一步骤,当FlexWrap设置Wrap,alignContent可以来改变,这里面有一个好玩的地方,就是其他的设置为默认,
一、如果FlexWrap设置为Wrap,alignContent可以控制,alginItems不能控制。
二、如果FlexWrap设置为NoWrap,alignContent不能控制,alginItems可以控制。
这样的特点就完全解决了我上面所说的矛盾。
来看gif,
百分比布局标签布局之FlexBoxLayout_第6张图片

showDivider属性

这个属性描述了FlowBoxLayout中,各个子view之间的用什么线条,和ListView的divider有点像。

来看看有多少个控制属性

  1. showDividerHorizontal (one or more of none | beginning | middle | end)
  2. dividerDrawableHorizontal (reference to a drawable)
  3. showDividerVertical(one or more of none | beginning | middle | end)
  4. dividerDrawableVertical (reference to a drawable)
  5. showDivider (one or more of none | beginning | middle | end)
  6. dividerDrawable (reference to a drawable)

dividerDrawableHorizontal(将水平分隔线放在伸缩线之间)

该属性的参数为一个drawable,配合showDivider或者showDividerHorizontal一起使用才会显示线条,其他显示效果无效

showDividerHorizontal

showDividerHorizontal有none | beginning | middle | end四个属性,none就是不显示线条,beginning显示线条在布局的上面,end显示线条在布局的下面,middle显示线条布局除上头和下的其他水平空隙

dividerDrawableVertical(将垂直分隔线放在伸缩线之间)

该属性的参数为一个drawable,配合showDivider或者showDividerVertical一起使用才会显示线条,其他显示效果无效

showDividerVertical

showDividerVertical有none | beginning | middle | end四个属性,none就是不显示线条,beginning显示线条在布局的左边,end显示线条在布局的右边,middle显示线条布局除去左和右的其他垂直空隙

dividerDrawable

该属性的参数为一个drawable,配合showDivider可以显示水平和垂直方向的线条,如果配合的是showDividerVertical,和showDividerVertical效果一样,只对垂直部分起作用,水平不起作用,如果配合的是showDividerHorizontal,和showDividerHorizontal效果一样,只对水平部分起作用,垂直不起作用,

showDivider

showDivider有none | beginning | middle | end四个属性,
配合dividerDrawableHorizontal就是showDividerHorizontal的效果,配合dividerDrawableVertical就是showDividerVertical的效果,配合dividerDrawable就是显示水平和垂直方向的线条

layout_order

这个属性是给子view设置的,按我的理解来的话,就是给view进行排序,谁的order权重大,谁就排后面,以此类推,如果没有设置order的话,那就按默认排列,

xml布局文件,该布局1和10我没有设置oder

com.google.android.flexbox.FlexboxLayout
        android:id="@+id/flexbox"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:alignContent="flex_start"
        app:alignItems="flex_start"
        app:flexWrap="wrap">

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:padding="3dp"
            android:text="1"
            android:textSize="20dp" />

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="2"
            android:textSize="20dp"
            app:layout_order="2" />

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="3"
            android:textSize="20dp"
            app:layout_order="3" />

        "110dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="4"
            android:textSize="20dp"
            app:layout_order="4" />

        "5"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="5"
            android:textSize="20dp" />

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="6"
            android:textSize="20dp"
            app:layout_order="6" />

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="7"
            android:textSize="20dp"
            app:layout_order="7" />

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="8"
            android:textSize="20dp"
            app:layout_order="8" />

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="9"
            android:textSize="20dp"
            app:layout_order="9" />

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="10"
            android:textSize="20dp" />
    

我们来看看gif,看看那一个好玩的东西。

百分比布局标签布局之FlexBoxLayout_第7张图片

当我们点击减少布局的时候发现,9是最后一个布局,应该点击删除的是9布局,但是删除的缺却是布局10,从这一点,我们可以推敲出,在该类中,并没有对整体的view进行排序,view还是按照原来的方式排列。

layout_flexGrow

这个参数有点像LinearLayout的weight,就是一行的数据,如果有空隙的话,他会自动增长填补空隙,默认值为1,现在,我们还是用上面的布局,我们给布局1和布局2设置相同的layout_flexGrow为2,我们来看看gif效果

百分比布局标签布局之FlexBoxLayout_第8张图片
从这个效果中我们看到,在删除的过程中,1和2都会自动的填充空余部分,并且1和2设置的都是相同的权值,那他们的增长也是一样的,添加也是一样,添加进来的view,1和2会同时一样的宽度进行缩小

layout_flexShrink

这个属性决定这个孩子如果在同一个Flex中包含的其他Flex项目的剩余自由空间被分配的时候会收缩多少

还是上面的布局,我们给布局1设置layout_flexShrink为20,给布局2设置layout_flexShrink为100,来看看gif

百分比布局标签布局之FlexBoxLayout_第9张图片

增加子view的时候,首先会把设置layout_flexShrink最大的布局2先当做空余空间占用,然后再来占用布局1

layout_minWidth / layout_minHeight

在NoWrap下,我们在增加子view的时候,其他view会伸缩自己宽度为给新进来的子view分配空余空间,假如,我们要其中的一个view不让他随着新进来的view而改变自己的宽度呢,这时候,我们在Direction为Row,FlexWrap为NoWrap的时候设置layout_minWidth为自己至少想要的宽度,在Direction为Column,FlexWrap为NoWrap的时候设置layout_minHeight为自己至少想要的高度,这样,在新进来的子view就不会挤压这个view了


        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:padding="3dp"
            android:text="1"
            android:textSize="20dp"

            app:layout_minHeight="20dp"
            />

layout_flexBasisPercent

这个属性是我这个里面看的最喜欢的属性了,对android适配简直好的没话讲,这个属性看名字就知道了,百分比布局,就是对布局子view的排列,我们可以按照百分比的样式进行排放子view,那对于在android上的适配可以做到特别好的帮助。

该属性默认值为-1,此属性仅在父长度确定时才有效(MeasureSpec mode is MeasureSpec.EXACTLY),意思就是match_parent或是指定高度或是宽度的时候,这个属性就能发挥他的作用。

我们设置先设置FlexWrap为Wrap,布局1的FlexBoxLayout为50,布局2的FlexBoxLayout为30,布局2的FlexBoxLayout设置为20,刚好100%,那么接下来其他的子view肯定会换行,我们来看看效果

        "80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:padding="3dp"
            android:text="1"
            app:layout_flexBasisPercent="50%"
            android:textSize="20dp" />

        "30%"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="2"
            android:textSize="20dp" />

        "20%"
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:background="@drawable/test_bg"
            android:gravity="center"
            android:text="3"
            android:textSize="20dp" />

百分比布局标签布局之FlexBoxLayout_第10张图片

正如我们自己所推想的,还是挺不错的一个功能。


从早上一边写一边看官网,一边测试,写一篇博客还是挺耗时间的,但是却乐此不疲

github demo链接

你可能感兴趣的:(源码分析)