Android自定义ViewGroup之实现FlowLayout流式布局
程序员文章站
2024-03-02 19:40:58
整理总结自鸿洋的博客:
一、flowlayout介绍
所谓flowlayout,就是控件根据viewgroup的宽,自动的往右添加,如果当前行剩...
整理总结自鸿洋的博客:
一、flowlayout介绍
所谓flowlayout,就是控件根据viewgroup的宽,自动的往右添加,如果当前行剩余空间不足,则自动添加到下一行。有点像所有的控件都往左飘的感觉,第一行满了,往第二行飘~所以也叫流式布局。android并没有提供流式布局,但是某些场合中,流式布局还是非常适合使用的,比如关键字标签,搜索热词列表等,比如下图:
github上已有现成的flowlayout,本文是从无到有去制作。
二、制作分析
1、对于flowlayout,需要指定的layoutparams,我们目前只需要能够识别margin即可,即使用marginlayoutparams.
2、onmeasure中计算所有childview的宽和高,然后根据childview的宽和高,计算自己的宽和高。(当然,如果不是wrap_content,直接使用父viewgroup传入的计算值即可)
3、onlayout中对所有的childview进行布局。
三、代码
1、mainactivity.java
public class mainactivity extends activity { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); // setcontentview(r.layout.activity_main2); // setcontentview(r.layout.activity_main3); } }
2、customviewgroup.java
public class customviewgroup extends viewgroup { private final string tag = getclass().getsimplename(); public customviewgroup(context context) { super(context); } public customviewgroup(context context, attributeset attrs) { super(context, attrs); } public customviewgroup(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); } /** * 一、重写generatelayoutparams,确定该viewgroup的layoutparams * 返回marginlayoutparams的实例,这样就为我们的viewgroup指定了其layoutparams为marginlayoutparams */ @override public layoutparams generatelayoutparams(attributeset attrs) { return new marginlayoutparams(getcontext(), attrs); } /** * 二、计算所有childview的宽度和高度 然后根据childview的计算结果,设置自己的宽和高 */ @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); //1、获得此viewgroup上级容器为其推荐的宽和高,以及计算模式 int widthmode = measurespec.getmode(widthmeasurespec); int heightmode = measurespec.getmode(heightmeasurespec); int sizewidth = measurespec.getsize(widthmeasurespec); int sizeheight = measurespec.getsize(heightmeasurespec); // 2、如果viewgroup布局是wrap_content时,根据childview的尺寸,计算容器的宽和高 int width = 0;//viewgroup的宽度 int height = 0;//viewgroup的高度 int linewidth = 0;//childview所占据的当前行总宽度 int lineheight = 0;//childview所占据的各行总高度 int ccount = getchildcount();////childview的数量 for(int i=0; i<ccount; i++){//遍历每个childview view childview = getchildat(i); measurechild(childview, widthmeasurespec, heightmeasurespec);// 测量当前child的宽和高 marginlayoutparams mlp = (marginlayoutparams) childview.getlayoutparams(); int cwidth = childview.getmeasuredwidth() + mlp.leftmargin + mlp.rightmargin; int cheight = childview.getmeasuredheight() + mlp.topmargin + mlp.bottommargin; if(linewidth + cwidth > sizewidth){//如果加入当前childview后超出最大宽度,width取最大高度,累加lineheight,然后开启新行 width = math.max(linewidth, cwidth); height += lineheight; linewidth = cwidth; }else{//如果加入当前childview后小于最大宽度,则累加linewidthheight lineheight取最大高度 linewidth += cwidth; height = math.max(lineheight, cheight); } if(i == ccount-1){// 如果是最后一个childview,则将当前记录的最大宽度和当前linewidth做比较 width = math.max(linewidth, cwidth); height += lineheight; } } //3、如果是wrap_content设置为我们计算的值;否则直接设置为父容器计算的值 setmeasureddimension( (widthmode == measurespec.exactly) ? sizewidth : width, (heightmode == measurespec.exactly) ? sizeheight : height ); } /** * 三、重写onlayout,对其所有childview进行定位(设置childview的绘制区域) */ private list<list<view>> allchildviews = new arraylist<list<view>>();//存储所有的childview,按行记录 private list<integer> maxlineheight = new arraylist<integer>();//存储每行的最大高度值 @override protected void onlayout(boolean changed, int l, int t, int r, int b) { allchildviews.clear(); maxlineheight.clear(); int width = getwidth();//每行的最大宽度 int linewidth = 0;//每行的即时宽度 int lineheight = 0;//每行的即时高度 list<view> linechildviews = new arraylist<view>();//存储每行所有的childview int ccount = getchildcount(); for(int i=0; i<ccount; i++){//遍历所有childview view childview = getchildat(i); marginlayoutparams mlp = (marginlayoutparams) childview.getlayoutparams(); int cwidth = childview.getmeasuredwidth(); int cheight = childview.getmeasuredheight(); if(linewidth + cwidth + mlp.leftmargin + mlp.rightmargin > width){//如果需要换行 maxlineheight.add(lineheight);// 存储这一行最大高度 allchildviews.add(linechildviews);// 将当前行的childview保存,然后开启新的arraylist保存下一行的childview linechildviews = new arraylist<view>(); linewidth = 0;// 重置行宽 }else{//如果不需要换行 linewidth += cwidth + mlp.leftmargin + mlp.rightmargin;//即时宽度累加 lineheight = math.max(lineheight,cheight + mlp.topmargin + mlp.bottommargin );//即时高度取最大值 linechildviews.add(childview);//把当前childview存入这一行的集合 } } // 记录最后一行 maxlineheight.add(lineheight); allchildviews.add(linechildviews); int left = 0;//左坐标 int top = 0;//上坐标 int linenums = allchildviews.size();// 得到总行数 for (int i = 0; i < linenums; i++) { linechildviews = allchildviews.get(i);// 取得每一行的所有的views lineheight = maxlineheight.get(i);// 取得当前行的最大高度 log.e(tag, "第" + i + "行 :" + linechildviews.size() + " , " + linechildviews); log.e(tag, "第" + i + "行, :" + lineheight); // 遍历当前行所有的view for (int j = 0; j < linechildviews.size(); j++) { view childview = linechildviews.get(j);//取得childview if (childview.getvisibility() == view.gone) { continue; } marginlayoutparams mlp = (marginlayoutparams) childview.getlayoutparams(); //计算childview的left,top,right,bottom int lc = left + mlp.leftmargin; int tc = top + mlp.topmargin; int rc = lc + childview.getmeasuredwidth(); int bc = tc + childview.getmeasuredheight(); log.e(tag, childview + " , l = " + lc + " , t = " + t + " , r =" + rc + " , b = " + bc); childview.layout(lc, tc, rc, bc);//设置这个childview的位置 left += childview.getmeasuredwidth() + mlp.rightmargin + mlp.leftmargin;//左坐标累加 } left = 0;//开始新的一行,左坐标重置 top += lineheight;//开始新的一行,上坐标累加 } } }
3、activity_main.xml
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#e1e6f6" android:orientation="vertical"> <com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup android:layout_width="fill_parent" android:layout_height="wrap_content"> <textview style="@style/text_flag_01" android:text="welcome" /> <textview style="@style/text_flag_01" android:text="it工程师" /> <textview style="@style/text_flag_01" android:text="学习ing" /> <textview style="@style/text_flag_01" android:text="恋爱ing" /> <textview style="@style/text_flag_01" android:text="挣钱ing" /> <textview style="@style/text_flag_01" android:text="努力ing" /> <textview style="@style/text_flag_01" android:text="i thick i can" /> </com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup> </linearlayout>
4、activity_main2.xml
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#e1e6f6" android:orientation="vertical"> <com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup android:layout_width="fill_parent" android:layout_height="wrap_content"> <textview style="@style/text_flag_01" android:text="welcome" /> <textview style="@style/text_flag_01" android:text="it工程师" /> <textview style="@style/text_flag_01" android:text="学习ing" /> <textview style="@style/text_flag_01" android:text="恋爱ing" /> <textview style="@style/text_flag_01" android:text="挣钱ing" /> <textview style="@style/text_flag_01" android:text="努力ing" /> <textview style="@style/text_flag_01" android:text="i thick i can" /> </com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup> <com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margintop="20dp"> <textview style="@style/text_flag_01" android:background="@drawable/flag_02" android:text="welcome" android:textcolor="#888888" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_02" android:text="it工程师" android:textcolor="#888888" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_02" android:text="学习ing" android:textcolor="#888888" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_02" android:text="恋爱ing" android:textcolor="#888888" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_02" android:text="挣钱ing" android:textcolor="#888888" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_02" android:text="努力ing" android:textcolor="#888888" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_02" android:text="i thick i can" android:textcolor="#888888" /> </com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup> <com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margintop="20dp"> <textview style="@style/text_flag_01" android:background="@drawable/flag_03" android:text="welcome" android:textcolor="#43bbe7" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_03" android:text="it工程师" android:textcolor="#43bbe7" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_03" android:text="学习ing" android:textcolor="#43bbe7" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_03" android:text="恋爱ing" android:textcolor="#43bbe7" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_03" android:text="挣钱ing" android:textcolor="#43bbe7" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_03" android:text="努力ing" android:textcolor="#43bbe7" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_03" android:text="i thick i can" android:textcolor="#43bbe7" /> </com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup> </linearlayout>
5、activity_main3.xml
<com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="200dp" android:layout_height="wrap_content" android:background="#ffffff"> <textview style="@style/text_flag_01" android:background="@drawable/flag_04" android:text="welcome" android:textcolor="#323232" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_04" android:text="it工程师" android:textcolor="#323232" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_04" android:text="学习ing" android:textcolor="#323232" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_04" android:text="恋爱ing" android:textcolor="#323232" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_04" android:text="挣钱ing" android:textcolor="#323232" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_04" android:text="努力ing" android:textcolor="#323232" /> <textview style="@style/text_flag_01" android:background="@drawable/flag_04" android:text="i thick i can" android:textcolor="#323232" /> </com.cctvjiatao.customviewgroupflowlayout.view.customviewgroup>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: vue之条件语句
下一篇: 4 比对到参考基因组输出bam文件