Android流式布局FlowLayout
自定义viewGroup实现流式布局
packagecom.example.flowlayout;importandroid.content.Context;importandroid.content.res.Resources;importandroid.util.AttributeSet;importandroid.util.Log;importandroid.util.TypedValue;importandroid.view.View;importandroid.view.ViewGroup;importjava.util.ArrayList;importjava.util.List;publicclassFlowLayoutextendsViewGroup{// item的横向、纵向间距,可以通过xml,在构造方法中设置privateintmHorizationSpacing=dp2px(16);privateintmVerticalSpacing=dp2px(8);privateList<List<View>>allViews=newArrayList<>();// 所有的行privateList<Integer>lineHeightList=newArrayList<>();// 每一行的行高publicFlowLayout(Contextcontext){super(context);}publicFlowLayout(Contextcontext,AttributeSetattrs){super(context,attrs);}publicFlowLayout(Contextcontext,AttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);}publicFlowLayout(Contextcontext,AttributeSetattrs,intdefStyleAttr,intdefStyleRes){super(context,attrs,defStyleAttr,defStyleRes);}@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){super.onMeasure(widthMeasureSpec,heightMeasureSpec);Log.e("flowlayout","onMeasure ===== ");clearMeasureParams();intchildCount=getChildCount();intpl=getPaddingLeft();intpr=getPaddingRight();intpt=getPaddingTop();intpb=getPaddingBottom();intselfWidth=MeasureSpec.getSize(widthMeasureSpec);intselfHeight=MeasureSpec.getSize(heightMeasureSpec);intselfNeedWidth=0;intselfNeedHeight=0;List<View>lineView=newArrayList<>();intlineUsedWhidth=0;intlineHeight=0;for(inti=0;i<childCount;i++){Viewchild=getChildAt(i);LayoutParamschildLayoutParams=child.getLayoutParams();// 将LayoutParams转换为子view的MeasureSpecintchildWidthMeasureSpec=getChildMeasureSpec(widthMeasureSpec,pl+pr,childLayoutParams.width);intchildHeightMeasureSpec=getChildMeasureSpec(heightMeasureSpec,pt+pb,childLayoutParams.height);// 分发给子view测量child.measure(childWidthMeasureSpec,childHeightMeasureSpec);// 测量完后就可以获得子view的宽高intchildMeasuredWidth=child.getMeasuredWidth();intchildMeasuredHeight=child.getMeasuredHeight();// 换行if(lineUsedWhidth+mHorizationSpacing+childMeasuredWidth+pl+pr>selfWidth){// 已经有的存储allViews.add(lineView);lineHeightList.add(lineHeight);// 保存数据selfNeedWidth=Math.max(selfNeedWidth,lineUsedWhidth+mHorizationSpacing);selfNeedHeight+=lineHeight+mVerticalSpacing;lineView=newArrayList<>();lineUsedWhidth=0;lineHeight=0;}// 流式布局,需要存放每一行已用的宽、当前行中最高值lineView.add(child);lineUsedWhidth+=childMeasuredWidth+mHorizationSpacing;lineHeight=Math.max(childMeasuredHeight,lineHeight);// 判断是否是最后一行if(i==childCount-1){// 已经有的存储allViews.add(lineView);lineHeightList.add(lineHeight);// 保存数据selfNeedWidth=Math.max(selfNeedWidth,lineUsedWhidth+mHorizationSpacing);selfNeedHeight+=lineHeight+mVerticalSpacing+pb+pt;}}intwidthMode=MeasureSpec.getMode(widthMeasureSpec);intheightMode=MeasureSpec.getMode(heightMeasureSpec);intrealWidth=widthMode==MeasureSpec.EXACTLY?selfWidth:selfNeedWidth;intrealHeight=heightMode==MeasureSpec.EXACTLY?selfHeight:selfNeedHeight;// 再测量自己的宽高setMeasuredDimension(realWidth,realHeight);}privatevoidclearMeasureParams(){allViews.clear();lineHeightList.clear();}@OverrideprotectedvoidonLayout(booleanchanged,intl,intt,intr,intb){Log.e("flowlayout","onLayout ===== ");intlineCount=allViews.size();intpaddingLeft=getPaddingLeft();intpaddingTop=getPaddingTop();for(inti=0;i<lineCount;i++){for(Viewview:allViews.get(i)){intleft=paddingLeft;inttop=paddingTop;intright=left+view.getMeasuredWidth();intbottom=top+view.getMeasuredHeight();view.layout(left,top,right,bottom);paddingLeft=right+mHorizationSpacing;}// 一行结束后,下一行的高paddingTop+=lineHeightList.get(i)+mVerticalSpacing;paddingLeft=getPaddingLeft();}}publicstaticintdp2px(intdp){return(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,Resources.getSystem().getDisplayMetrics());}}在xml中使用
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.example.flowlayout.FlowLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_500"android:padding="15dp"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="洗脸巾"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="相机"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="化妆水"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="邮箱贴纸"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="移ddddd"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="z"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="数据"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="纸"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="纸"/><TextViewandroid:layout_width="wrap_content"android:layout_height="50dp"android:background="@color/purple_200"android:padding="5dp"android:text="手机保护壳"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="手机充电线"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@color/purple_200"android:padding="5dp"android:text="实测中"/></com.example.flowlayout.FlowLayout></LinearLayout>