TagFlowLayout组件是来自鸿洋提供的一个流式布局的框架,建议先看这篇文章修改FlowLayout源码,让其支持设置最大行数
这里直接贴上代码
/**
* 用于布局TagView标签容器的流式布局
* Change by mChenys on 2019/1/8.
* 修改后,支持子View响应点击事件,支持根据OnTagClickListener#onTagClick的返回值来处理状态
* 提供外部调用doSelect方法改变item状态
*/
public class TagFlowLayout extends FlowLayout
implements TagAdapter.OnDataChangedListener {
private TagAdapter mTagAdapter;
private int mSelectedMax = -1;//-1为不限制数量
private static final String TAG = "TagFlowLayout";
//所有已选择的TagView的位置
private Set<Integer> mSelectedView = new HashSet<Integer>();
public interface OnSelectListener {
void onSelected(Set<Integer> selectPosSet);
}
//新增点击事件监听
public interface OnTagClickListener {
boolean onTagClick(View view, int position, TagFlowLayout parent);
}
private OnSelectListener mOnSelectListener;
private OnTagClickListener mOnTagClickListener;
public void setOnSelectListener(OnSelectListener onSelectListener) {
mOnSelectListener = onSelectListener;
}
public void setOnTagClickListener(OnTagClickListener onTagClickListener) {
mOnTagClickListener = onTagClickListener;
}
public TagFlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout);
mSelectedMax = ta.getInt(R.styleable.TagFlowLayout_max_select, -1);
ta.recycle();
}
public TagFlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TagFlowLayout(Context context) {
this(context, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
TagView tagView = (TagView) getChildAt(i);
if (tagView.getVisibility() == View.GONE) {
continue;
}
if (tagView.getTagView().getVisibility() == View.GONE) {
tagView.setVisibility(View.GONE);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setAdapter(TagAdapter adapter) {
mTagAdapter = adapter;
mTagAdapter.setOnDataChangedListener(this);
mSelectedView.clear();
changeAdapter();
}
@SuppressWarnings("ResourceType")
private void changeAdapter() {
removeAllViews();
TagAdapter adapter = mTagAdapter;
TagView tagViewContainer = null;//存放标签的tag容器
HashSet preCheckedList = mTagAdapter.getPreCheckedList();
for (int i = 0; i < adapter.getCount(); i++) {
//初始化自定义布局
View tagView = adapter.getView(this, i, adapter.getItem(i));
//创建存放标签的容器
tagViewContainer = new TagView(getContext());
//将父控件状态变化强加到其子控件中,这样就可以通过改变父控件的状态来改变其包裹的子View状态
tagView.setDuplicateParentStateEnabled(true);
if (tagView.getLayoutParams() != null) { //只有通过inflate的时候传入了parent才会有布局参数
//将自定义的布局数据设置到tag容器中
tagViewContainer.setLayoutParams(tagView.getLayoutParams());
} else {
MarginLayoutParams lp = new MarginLayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.setMargins(dip2px(getContext(), 5),
dip2px(getContext(), 5),
dip2px(getContext(), 5),
dip2px(getContext(), 5));
tagViewContainer.setLayoutParams(lp);
}
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
tagView.setLayoutParams(lp);
//添加自定义的布局到tag容器中
tagViewContainer.addView(tagView);
//将容器添加到流式布局中
addView(tagViewContainer);
//设置预定义选中的view的状态
if (preCheckedList.contains(i)) {
setChildChecked(i, tagViewContainer);
}
//判断列表中那些需要动态设置状态的
if (mTagAdapter.setSelected(i, adapter.getItem(i))) {
setChildChecked(i, tagViewContainer);
}
//去掉指定布局的焦点(去掉后子View就响应不了点击事件了)
//tagView.setClickable(false);
final int position = i;
//tag容器的点击事件
tagViewContainer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mOnTagClickListener != null) {
//获取点击事件的结果,如果成功,则处理doSelect
boolean success = mOnTagClickListener.onTagClick(v, position, TagFlowLayout.this);
if (success) {
//处理选择
doSelect((TagView) v, position);
}
} else {
//处理选择
doSelect((TagView) v, position);
}
}
});
}
mSelectedView.addAll(preCheckedList);
}
public void setMaxSelectCount(int count) {
if (mSelectedView.size() > count) {
Log.w(TAG, "you has already select more than " + count + " views , so it will be clear .");
mSelectedView.clear();
}
mSelectedMax = count;
}
public Set<Integer> getSelectedList() {
return new HashSet<Integer>(mSelectedView);
}
private void setChildChecked(int position, TagView view) {
view.setChecked(true);
mTagAdapter.onSelected(position, view.getTagView());
}
private void setChildUnChecked(int position, TagView view) {
view.setChecked(false);
mTagAdapter.unSelected(position, view.getTagView());
}
/**
* 外部调用,手动修改状态
*
* @param position
*/
public void doSelect(int position) {
TagView tagView = (TagView) getChildAt(position);
doSelect(tagView, position);
}
//处理tag容器的点击事件,改变view的选中状态和记录选中的索引
private void doSelect(TagView child, int position) {
if (!child.isChecked()) {
//未选中->已选中
//处理max_select=1的情况,(单选)
if (mSelectedMax == 1 && mSelectedView.size() == 1) {
Iterator<Integer> iterator = mSelectedView.iterator();
Integer preIndex = iterator.next();
TagView pre = (TagView) getChildAt(preIndex);
setChildUnChecked(preIndex, pre);//重置上一次选择的TagView状态
setChildChecked(position, child);
mSelectedView.remove(preIndex);
mSelectedView.add(position);
} else {//多选
if (mSelectedMax > 0 && mSelectedView.size() >= mSelectedMax) {
//超过最大数不能继续选择
return;
}
//mSelectedMax=-1,不限个数(默认)
setChildChecked(position, child);
mSelectedView.add(position);
}
} else {
//已选中->未选中
if (mSelectedMax == 1) {
//单选不作处理
return;
}
setChildUnChecked(position, child);
mSelectedView.remove(position);
}
//实时通知选当前选中的view的index
if (mOnSelectListener != null) {
mOnSelectListener.onSelected(new HashSet<Integer>(mSelectedView));
}
}
public TagAdapter getAdapter() {
return mTagAdapter;
}
private static final String KEY_CHOOSE_POS = "key_choose_pos";
private static final String KEY_DEFAULT = "key_default";
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_DEFAULT, super.onSaveInstanceState());
String selectPos = "";
if (mSelectedView.size() > 0) {
for (int key : mSelectedView) {
selectPos += key + "|";
}
selectPos = selectPos.substring(0, selectPos.length() - 1);
}
//保存存储的数据
bundle.putString(KEY_CHOOSE_POS, selectPos);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
//恢复存储的数据
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
String mSelectPos = bundle.getString(KEY_CHOOSE_POS);
if (!TextUtils.isEmpty(mSelectPos)) {
String[] split = mSelectPos.split("\\|");
for (String pos : split) {
int index = Integer.parseInt(pos);
mSelectedView.add(index);
TagView tagView = (TagView) getChildAt(index);
if (tagView != null) {
setChildChecked(index, tagView);
}
}
}
super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT));
return;
}
super.onRestoreInstanceState(state);
}
@Override
public void onChanged() {
mSelectedView.clear();
changeAdapter();
}
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}