最近有这么一个需求,如下图
开发中内容搜索页面经常会记录搜索关键字,搜索关键字长度不一,我们通过会采用自定义流布局的方式展示;流布局的基本需要是动态添加childView并实现自动换行操作,这个操作比较简单,重写ViewGroup的onMeasure()方法,遍历动态计算每个View的宽高,宽度累加,当超过ViewGroup宽度时,则换行显示,负责设置子控件的测量模式和大小,根据所有子控件设置自己的宽和高;然后重写onLayout()方法,完成对所有的childView的位置以及大小的指定;
我们有时候也会显示用户标签,标签长度不一,标签不光可以点击,还可以选中多个标签,那么我们是否可以封装一个常见流布局的呢?当然可以,我封装一个支持行数控制,单选,多选,点击等操作的流布局控件;
1.对外暴露关键参数
首先加了几个对外暴露的变量
- 变量limitLineCount表示默认显示的行数,变量isLimitLine表示是否有行数限制,这个是根据自身去求动态设置的;
- 另外一个参数isOverFlow是否溢出,因为接口返回的数据数量是不确定的,可能不会超过行限制,也可能超过行限制,如果超过,则显示点击显示全部按钮,所以这个参数是起到这个作用的;
- 变量mOnTagClickListener和mOnTagSelectListener分别表示标签点击和标签选中事件回调;
- 变量mTagCheckMode表示标签选中模式,点击,单选,多选;
- 变量isMoreListener表示是否需要显示更多按钮,即超出要显示的行数;
/**
* 流布局不支持被选中
*/
public static final int FLOW_TAG_CHECKED_NONE = 0;
/**
* 流布局支持单选
*/
public static final int FLOW_TAG_CHECKED_SINGLE = 1;
/**
* 流布局支持多选
*/
public static final int FLOW_TAG_CHECKED_MULTI = 2;
/**
* 监听数据集变化
*/
AdapterDataSetObserver mDataSetObserver;
/**
* 含有数据及显示视图的Adapter
*/
ListAdapter mAdapter;
/**
* 标签点击事件回调
*/
OnTagClickListener mOnTagClickListener;
/**
* 标签被选中事件回调
*/
OnTagSelectListener mOnTagSelectListener;
/**
* 是否有行限制
*/
boolean isLimitLine = true;
/**
* 限制显示的行数
*/
int limitLineCount = 1;
/**
* 是否溢出,即超过要求显示行数
*/
boolean isOverFlow;
/**
* 标签流式布局选中模式,默认是不支持选中的
*/
private int mTagCheckMode = FLOW_TAG_CHECKED_NONE;
/**
* 存储选中的tag
*/
private SparseBooleanArray mCheckedTagArray = new SparseBooleanArray();
/**
* 超过限制显示行数函数回调
*/
private IsMoreListener isMoreListener;
2.测量时做行数限制
如果超过,则不继续测量高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获得它的父容器为它设置的测量模式和大小
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获取Padding
// 获得它的父容器为它设置的测量模式和大小
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
//FlowLayout最终的宽度和高度值
int resultWidth = 0;
int resultHeight = 0;
//测量时每一行的宽度,width不断取最大宽度
int lineWidth = 0;
//测量时每一行的高度,加起来就是FlowLayout的高度
int lineHeight = 0;
//流布局的行数
int currLines = 0;
//流布局子视图的数量
int chi