流式布局
public class FlowLayout extends ViewGroup {
private ArrayList<View> lineViews;
private ArrayList<ArrayList<View>> allViews;
public FlowLayout(Context context) {
this(context, null);
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
lineViews = new ArrayList<>();
allViews = new ArrayList<>();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//最后测量的高度
int height = 0;
//最后测量的宽度
int width = 0;
lineViews.clear();
allViews.clear();
//记录行的高度
int lineHeight = 0;
//记录行的宽度
int lineWidth = 0;
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
//测量子View的大小
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams params = (MarginLayoutParams) childView.getLayoutParams();
int childHeight = childView.getMeasuredHeight() + params.topMargin + params.bottomMargin;
int childWidth = childView.getMeasuredWidth() + params.leftMargin + params.rightMargin;
//如果当前行宽+子view的宽度大于父控件给的宽度,则表示要转行
if (lineWidth + childWidth > widthSize - getPaddingLeft() - getPaddingRight()) {
width = Math.max(width, lineWidth);
height += lineHeight;
//重置行的宽和高
lineWidth = childWidth;
lineHeight = childHeight;
allViews.add(lineViews);
lineViews = new ArrayList<>();
//lineViews.clear();
lineViews.add(childView);
} else {//不转行
//行高为当前行中子View高度最高的
lineHeight = Math.max(childHeight, lineHeight);
//行宽为子View宽度相加
lineWidth += childWidth;
lineViews.add(childView);
}
//如果是最后一行,则要加上最后一行的高度和与之前的宽度比较
if (i == getChildCount() - 1) {
height += lineHeight + getPaddingTop() + getPaddingBottom();
width = Math.max(width, lineWidth);
allViews.add(lineViews);
}
}
setMeasuredDimension(
widthMode == MeasureSpec.AT_MOST ? width : widthSize,
heightMode == MeasureSpec.AT_MOST ? height : heightSize);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int w = getPaddingLeft();
int h = getPaddingTop();
int hh = 0;
for (int i = 0; i < allViews.size(); i++) {
for (int j = 0; j < allViews.get(i).size(); j++) {
View child = allViews.get(i).get(j);
if (child.getVisibility() == View.GONE) continue;
MarginLayoutParams param = (MarginLayoutParams) child.getLayoutParams();
int lc = param.leftMargin;
int tc = param.topMargin;
int rc = lc + child.getMeasuredWidth();
int bc = tc + child.getMeasuredHeight();
child.layout(lc + w, tc + h, rc + w, bc + h);
w += (rc + param.rightMargin);
hh = Math.max(bc + param.bottomMargin, hh);
}
w = getPaddingLeft();
h += hh;
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
}