修改FlowLayout源码,让其支持设置最大行数

这里所说的FlowLayout组件是来自鸿洋提供的一个流式布局的框架
框架源码看这里
框架作者博客介绍看这里

废话不多说,直接上代码,主要就是修改FlowLayout的onMeasure和onLayout方法,同时我这里还对onLayout方法优化了一下,减少了一次for循环处理行view,行高,行宽等信息

package cn.com.pconline.shopping.common.widget.flowlayout;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.text.TextUtilsCompat;
import android.util.AttributeSet;
import android.util.LayoutDirection;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

import cn.com.pc.framwork.utils.app.LogUtils;
import cn.com.pconline.shopping.R;


/**
 * 流式布局  https://github.com/hongyangAndroid/FlowLayout
 * 

* Change by mChenys on 2019/1/8. * 修改后,支持行数限制,优化了在onLayout的时候的二次循环初始化参数,支持获取当前可见的item个数 */ public class FlowLayout extends ViewGroup { private static final String TAG = "FlowLayout"; protected static final int LEFT = -1; protected static final int CENTER = 0; protected static final int RIGHT = 1; protected List<List<View>> mAllViews = new ArrayList<List<View>>();//记录所有行 protected List<Integer> mLineHeight = new ArrayList<Integer>();//记录所有行高 protected List<Integer> mLineWidth = new ArrayList<Integer>();//记录所有行宽 protected List<View> lineViews = new ArrayList<>();//临时记录每行的view protected int mGravity; private int maxLine = -1;//最大行数 private boolean isExceedingMaxLimit; //预设的子View是否超出了最大行数限制 public void setMaxLine(int maxLine) { this.maxLine = maxLine; } public FlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout); mGravity = ta.getInt(R.styleable.TagFlowLayout_tag_gravity, LEFT); int layoutDirection = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()); if (layoutDirection == LayoutDirection.RTL) { if (mGravity == LEFT) { mGravity = RIGHT; } else { mGravity = LEFT; } } ta.recycle(); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context) { this(context, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mAllViews.clear();//记录所有行的view mLineHeight.clear();//记录每一行的高度 mLineWidth.clear();//记录每一行的宽度 lineViews.clear();//记录每一行的view int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // wrap_content 最终宽高 int width = 0; int height = 0; //当前已用行宽高 int lineWidth = 0; int lineHeight = 0; int cCount = getChildCount(); LogUtils.e("cys", "cCount:" + cCount); for (int i = 0; i < cCount; i++) { View child = getChildAt(i); if (child.getVisibility() == View.GONE) { continue; } //测量子view measureChild(child, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); //子View宽高 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) { if (maxLine > 0 && mAllViews.size() + 1 >= maxLine) { //+1是因为后面还有最后一行 isExceedingMaxLimit = true; break;//超过最大行数跳出循环 } //需要换行 if (i == 0 && width == 0 && lineWidth == 0 && height == 0 && lineHeight == 0) { //如果第一个子View就满足换行条件,那么width和height就是子View的宽高 width = lineWidth = childWidth; height = lineHeight = childHeight; lineViews.add(child); } else { width = Math.max(width, lineWidth);//记录最大行宽 height += lineHeight;//累加包裹内容所需的高度 } //换行前,保存当前行数据 mLineHeight.add(lineHeight); mLineWidth.add(lineWidth); mAllViews.add(lineViews); //换行,新行数据初始化 lineWidth = 0;//重新赋值行宽 lineHeight = 0;//重新赋值行高 lineViews = new ArrayList<View>();//创建新行 if (i == 0 && width > 0 && height > 0) { //如果第一个子View就满足换行条件并且数据已经保存,则不需要下面重复添加了 continue; } } //新行或者当前行继续添加子View lineWidth += childWidth;//累加行宽 lineHeight = Math.max(lineHeight, childHeight);//取当前行最大高度作为行高 lineViews.add(child); } //添加最后一行数据 width = Math.max(lineWidth, width);//包裹内容所需的最大宽度 height += lineHeight;//累加高度 mLineHeight.add(lineHeight); mLineWidth.add(lineWidth); mAllViews.add(lineViews); setMeasuredDimension( //父控件宽高确定则用确定的,否则用测量后的 modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(), modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()// ); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { LogUtils.e("cys","onLayout"); //总宽 int width = getWidth(); //当前已用行宽高 int lineHeight = 0; //下面是对每一行的View进行布局 int left = getPaddingLeft(); int top = getPaddingTop(); int lineNum = mAllViews.size(); for (int i = 0; i < lineNum; i++) { //获取当前行和行高 lineViews = mAllViews.get(i); lineHeight = mLineHeight.get(i); // set gravity int currentLineWidth = this.mLineWidth.get(i); switch (this.mGravity) { case LEFT: left = getPaddingLeft(); break; case CENTER: left = (width - currentLineWidth) / 2 + getPaddingLeft(); break; case RIGHT: // 适配了rtl,需要补偿一个padding值 ,从右边向左开始布局 left = width - (currentLineWidth + getPaddingLeft()) - getPaddingRight(); // 适配了rtl,需要把lineViews里面的数组倒序排,从右边开始存放view Collections.reverse(lineViews); break; } //开始布局 for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); if (child.getVisibility() == View.GONE) { continue; } MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); int 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); //更新下一个view添加到当前行的left left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } //更新下一个view添加到下一行的top top += lineHeight; } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected LayoutParams generateDefaultLayoutParams() { return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } @Override protected LayoutParams generateLayoutParams(LayoutParams p) { return new MarginLayoutParams(p); } /** * 获取指定行数内的item个数 * * @return 每行的个数之和 * @lineNum 总行数 */ public int getTotalByLine(int lineNum) { int count = 0; if (lineNum <= mAllViews.size()) { for (int i = 0; i < lineNum; i++) { List<View> line = mAllViews.get(i); count += line.size(); } } else { for (int i = 0; i < mAllViews.size(); i++) { List<View> line = mAllViews.get(i); count += line.size(); } } return count; } /** * 返回总行数 * * @return */ public int getTotalLine() { return mAllViews.size(); } /** * 设置的数据是否超过了最大限制 * * @return */ public boolean isExceedingMaxLimit() { return isExceedingMaxLimit; } }

你可能感兴趣的:(Android)