最近在项目中药使用流式布局,但是在网上找的都不能满足要求,这篇博客内容只支持match_parent,我改后的代码可以支持wrap_content,原文也仅仅是少加一行高度而已。。新博客希望大家多多评论。。原文链接


一:概述:

1.流式布局的特点以及应用场景
特点:当上面一行的空间不够容纳新的TextView时候,
才开辟下一行的空间

场景:主要用于关键词搜索或者热门标签等场景
2.自定义ViewGroup,重点重写下面两个方法
1、onMeasure:测量子view的宽高,设置自己的宽和高
2、onLayout:设置子view的位置
onMeasure:根据子view的布局文件中属性,来为子view设置测量模式和测量值
测量=测量模式+测量值;
测量模式有3种:
EXACTLY:表示设置了精确的值,一般当childView设置其宽、高为精确值、match_parent时,ViewGroup会将其设置为EXACTLY;
AT_MOST:表示子布局被限制在一个最大值内,一般当childView设置其宽、高为wrap_content时,ViewGroup会将其设置为AT_MOST;
UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此种模式比较少见。
3.LayoutParams
ViewGroup LayoutParams :每个 ViewGroup 对应一个 LayoutParams; 即 ViewGroup -> LayoutParams
getLayoutParams 不知道转为哪个对应的LayoutParams ,其实很简单,就是如下:
子View.getLayoutParams 得到的LayoutParams对应的就是 子View所在的父控件的LayoutParams;
例如,LinearLayout 里面的子view.getLayoutParams ->LinearLayout.LayoutParams
所以 咱们的FlowLayout 也需要一个LayoutParams,由于上面的效果图是子View的 margin,
所以应该使用MarginLayoutParams。即FlowLayout->MarginLayoutParams
4.最后来看看实现的最终效果图:

二:代码

  1. 自定义热门标签的ViewGroup实现
      根据上面的技术分析,自定义类继承于ViewGroup,并重写 onMeasure和onLayout等方法。具体实现代码如下:
      我主要改了原文中onMeasure中的一些代码,让它可以包裹内容
      
    1,自定义flowlayout代码
package com.yaofangwang.flowlayout;import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;import java.util.ArrayList;
import java.util.List;public class FlowGroupView extends ViewGroup  {/*** 储存所有的view 按行记录*/private List<List<View>> mAllViews = new ArrayList<List<View>>();/*** 记录每一行的高度*/private List<Integer> mLineHeight = new ArrayList<Integer>();private String TAG = "TAG";public FlowGroupView(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);}public FlowGroupView(Context context, AttributeSet attrs) {super(context, attrs);}public FlowGroupView(Context context) {super(context);}
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 置空 view 容器 和 lineHeight 容器  重新赋值//因为OnMeasure方法会走两次,第一次是实例化这个对象的时候高度和宽度都是0//之后走了OnSizeChange()方法后 又走了一次OnMeasure,所以要把第一次加进去的数据清空。mAllViews.clear();mLineHeight.clear();//得到上级容器为其推荐的宽高和计算模式int specWidthMode = MeasureSpec.getMode(widthMeasureSpec);int specHeighMode = MeasureSpec.getMode(heightMeasureSpec);int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);int specHeighSize = MeasureSpec.getSize(heightMeasureSpec);// 计算出所有的 child 的 宽和高
//      measureChildren(specWidthSize, specHeighSize);// 记录如果是 warp_content 是设置的宽和高int width = 0;int height = 0;// 得到子view的个数int cCount = getChildCount();/*** 记录每一行的宽度,width不断取最大宽度*/int lineWidth = 0;/*** 每一行的高度,累加至height*/int lineHeight = 0;// 存储每一行所有的childViewList<View> lineViews = new ArrayList<View>();for (int i = 0; i < cCount; i++) {// 得到每个子ViewView child = getChildAt(i);// 测量每个子View的宽高measureChild(child, widthMeasureSpec, heightMeasureSpec);// 当前子view的lpMarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();// 子view的宽和高int cWidth = 0;int cheight = 0;// 当前子 view 实际占的宽cWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;// 当前子View 实际占的高cheight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;lineHeight=cheight;// 需要换行if(lineWidth + cWidth > specWidthSize){width = Math.max(lineWidth, cWidth);// 取最大值lineWidth = cWidth; // 开启新行的时候重新累加width// 开启新行时累加 height
//              lineHeight = cheight; // 记录下一行的高度mAllViews.add(lineViews);mLineHeight.add(cheight);lineViews = new ArrayList<>();// 换行的时候把该 view 放进 集合里lineViews.add(child);// 这个  view(child) 是下一行的第一个viewheight += cheight; //每个View高度是一样的,直接累加Log.e("需要换行", "hight--" + height);Log.e("onMeasure", "AllViews.size()  --  > " + mAllViews.size());}else {// 不需要换行lineWidth += cWidth;//Log.e("不需要换行","hight--"+height);// 不需要换行时 把子View add 进集合lineViews.add(child);}if(i == cCount-1){// 如果是最后一个viewwidth = Math.max(lineWidth, cWidth);height += cheight;Log.e("最后一个view","hight--"+height);}}// 循环结束后 把最后一行内容add进集合中mLineHeight.add(lineHeight); // 记录最后一行mAllViews.add(lineViews);// MeasureSpec.EXACTLY 表示设置了精确的值// 如果 mode 是 MeasureSpec.EXACTLY 时候,则不是 warp_content 用计算来的值,否则则用上级布局分给它的值setMeasuredDimension(specWidthMode == MeasureSpec.EXACTLY ? specWidthSize : width,specHeighMode == MeasureSpec.EXACTLY ? specHeighSize : height);Log.e("onMeasure", "mAllViews.size() -- > " + mAllViews.size() + "   mLineHeight.size() -- > " + mLineHeight.size() + "Height -- > "+height);}/*** 所有childView的位置的布局*/@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// 当前行的最大高度int lineHeight = 0;// 存储每一行所有的childViewList<View> lineViews = new ArrayList<View>();int left = 0;int top = 0;// 得到总行数int lineNums = mAllViews.size();for (int i = 0; i < lineNums; i++){// 每一行的所有的viewslineViews = mAllViews.get(i);// 当前行的最大高度lineHeight = mLineHeight.get(i);Log.e("onLayout" , "第" + i + "行 :" + lineViews.size()+"-------lineHeight"+ lineHeight);// 遍历当前行所有的Viewfor (int j = 0; j < lineViews.size(); j++){View child = lineViews.get(j);if (child.getVisibility() == View.GONE){continue;}MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();//计算childView的left,top,right,bottomint lc = left + lp.leftMargin;int tc = top + lp.topMargin;int rc =lc + child.getMeasuredWidth();int bc = tc + child.getMeasuredHeight();child.layout(lc, tc, rc, bc);left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;}left = 0;top += lineHeight;}Log.v("onLayout", "onLayout   mAllViews.size() -- > " + mAllViews.size() + "   mLineHeight.size() -- > "+ mLineHeight.size());}/*** 这个一定要设置,否则会包强转错误* 设置它支持 marginLayoutParams*/@Overridepublic ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(),attrs);}
}

2,布局文件

 <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/layout"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><com.yaofangwang.flowlayout.FlowGroupViewandroid:id="@+id/flowgroupview"android:layout_width="match_parent"android:layout_height="wrap_content"></com.yaofangwang.flowlayout.FlowGroupView></LinearLayout>

3,TextView的样式文件:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >  <solid android:color="#666666" />  <corners android:radius="10dp" />  <padding   android:left="5dp"  android:right="5dp"  android:top="5dp"  android:bottom="5dp"   />  </shape> 

4,使用该布局的类

ArrayList<String> names = new ArrayList<String>();FlowGroupView view;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setData();view = (FlowGroupView) findViewById(R.id.flowgroupview);for (int i = 0; i < names.size(); i++) {addTextView(names.get(i));}}/*** 动态添加布局* @param str*/private void addTextView(String str) {TextView child = new TextView(this);ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.WRAP_CONTENT, ViewGroup.MarginLayoutParams.WRAP_CONTENT);params.setMargins(15, 15, 15, 15);child.setLayoutParams(params);child.setBackgroundResource(R.drawable.shape_textback);child.setText(str);child.setTextColor(Color.WHITE);initEvents(child);//监听view.addView(child);}/*** 为每个view 添加点击事件*/private void initEvents(final TextView tv){tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubToast.makeText(MainActivity.this, tv.getText().toString(), 0).show();}});}private void setData(){names.add("降龙十八掌");names.add("黯然销魂掌");names.add("左右互搏术");names.add("七十二路空明拳");names.add("小无相功");names.add("拈花指");names.add("打狗棍法");names.add("蛤蟆功");names.add("九阴白骨爪");names.add("一招半式闯江湖");names.add("醉拳");names.add("龙蛇虎豹");names.add("葵花宝典");names.add("吸星大法");names.add("如来神掌警示牌");}

解决:Android中常见的热门标签的流式布局flowlayout不能wrap_content相关推荐

  1. android 流失标签,Android中常见的热门标签的流式布局的实现

    一.概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出) 类似的自 ...

  2. android实现标签功能,Android实现热门标签的流式布局

    一.概述: 在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出) 类似的 ...

  3. android 自定义flowlayout,Android 流式布局FlowLayout 实现关键字标签

    FlowLayout Android 流式布局FlowLayout 实现关键字标签 效果图 使用方法 在项目根目录的build.gradle文件中加入如下代码 maven { url "ht ...

  4. Android自定义流式布局-FlowLayout

    很多App在搜索页时都有对热门标签的一个排列,而Android官方没有对应的布局控件,所以自己写了一个流式布局(也称标签布局)--FlowLayout. 为了大家使用的方便,没有添加自定义属性,所以需 ...

  5. Android流式布局FlowLayout,一款针对Tag的布局

    交流群 : 668524118 本群主要用于编程技术 ,及创意作品 ,思维架构的交流 ,欢迎喜欢创新 ,热爱生活的朋友加入 ! 前言 flow layout, 流式布局, 这个概念在移动端或者前端开发 ...

  6. Android第三方流式布局FlowLayout简单实用(搜索历史记录)

    效果图: 导入大Model下: maven { url 'https://jitpack.io' } builde.gradle依赖: implementation 'com.github.LRH19 ...

  7. Android 流式布局FlowLayout

    这个是在GitHub上看到的,GitHub地址:https://github.com/blazsolar/FlowLayout 用FlowLayout方便了很多,这是一个很强大的自定义控件,向原作者致 ...

  8. Android中的封装流式布局FlowLayout

    鸿洋的GitHub:https://github.com/hongyangAndroid/FlowLayout 第一步:加依赖 implementation 'com.hyman:flowlayout ...

  9. Java中的流式布局(FlowLayout)

    Flowlayout默认居中对齐(FlowLayout.LEFT),组件之间的默认水平和垂直间隙为5px,组件的大小为默认的最佳大小(比如按钮的大小会保证刚好显示按钮名). 用add方法添加组件,且组 ...

  10. android自定义view流布局,Android控件进阶-自定义流式布局和热门标签控件

    一.概述: 在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧 类似的自定义换行流式布局控件.下 ...

最新文章

  1. MySQL基础篇:用户和权限管理
  2. 在malloc函数中为什么常用sizeof来设定内存分配的大小?
  3. java hprof_java 性能之 hprof
  4. deactivate_sending在创建新的table entry时的作用
  5. exp导出excel oracle_如何从Oracle快速导出数据到Excel
  6. 【SAS NOTE】数组
  7. # 华为考试心路历程#一名小白的HCNP数通取证记录
  8. Yarn install报错 【错误: 找不到或无法加载主类 install】
  9. julia 使用修改后的pkg
  10. win10安装小爱同学 UWP
  11. 曾维沛云推广:全网落地营销为广西南宁企业带来精准客户订单
  12. 支持查看朋友圈的微信Mac版客户端
  13. VMware16安装MacOS【详细教程】
  14. 关于在POI以SAX方式解析,会导出拼音(音标)的问题解决
  15. c语言变量是如何存储,C语言变量存储
  16. 《信息保障和安全》第五章
  17. dede首页php调用会员积分,dedecms织梦添加会员积分的方法
  18. 短信接口调用-手机短信,验证码
  19. 如何快速地将CAD转换成Excel?
  20. 最常用计算机机箱,好看又实用 给你的电脑选一个好机箱

热门文章

  1. 揭秘骗术:黑客人肉、查开房的灰色项目
  2. 利用WireShark下载视频网站的流媒体视频
  3. 获取取本月一号、本月月末 日期
  4. 【数据库原理及应用教程(第4版|微课版)陈志泊】【第一章习题】
  5. 香港消委会:大部分航空公司超卖机票无赔偿细则
  6. 关于通过邮箱找回密码的实现
  7. 推荐:本人使用频率最高的20款Mac软件(全)
  8. unity篇-官方序列化接口 ISerializationCallbackReceiver
  9. 人行各地中支征信服务“再升级”
  10. 脱壳之aspack压缩壳