android 换行乱_Android自动换行布局

public class FlowLayout extends ViewGroup {

/**

* 所有子控件的容器

*/

private List> lineList = new ArrayList<>();

/**

* 每行的高度

*/

private List lineHeightList = new ArrayList<>();

/**

* 防止多次测量

*/

private boolean measureFlag = true;

public FlowLayout(Context context) {

super(context);

}

public FlowLayout(Context context, AttributeSet attrs) {

super(context, attrs);

}

public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@Override

public LayoutParams generateLayoutParams(AttributeSet attrs) {

return new MarginLayoutParams(getContext(), attrs);

}

/**

* 在被调用这个方法之前 它的父容器 已经把它的测量模式改成了当前控件的测量模式

*

* @param widthMeasureSpec

* @param heightMeasureSpec

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//获取到父容器 给我们的参考值

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

//获取到自己的测量模式

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

//记录当前控件里面的子控件的总高宽

int childMaxWidth = 0;

int childCountHeight = 0;

//防止多次测量

if (measureFlag) {

measureFlag = false;

} else {

//当前一行,控件中的子控件的总宽度

int lineCountWidth = 0;

//当前一行,最高子控件的高度

int lineMaxHeight = 0;

//记录每个子控件的宽高

int childWidth, childHeight;

//创建一行空容器

List viewList = new ArrayList<>();

int childCount = getChildCount();

for (int i = 0; i < childCount; i++) {

View childView = getChildAt(i);

//先测量子控件

measureChild(childView, widthMeasureSpec, heightMeasureSpec);

MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();

//计算当前子控件的实际宽高

childWidth = childView.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;

childHeight = childView.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;

//如果当前行的宽度,加上这个view的宽度,大于容器的宽度时,就换行

if (lineCountWidth + childWidth + getPaddingLeft() + getPaddingRight() > widthSize) {

//需要换行的情况

//每次进入到这里的时候 只是保存了上一行的信息,并没有保存当前行的信息

//拿到所有行中,最大的宽,去决定EXACTLY时的最大宽度

childMaxWidth = Math.max(childMaxWidth, lineCountWidth);

childCountHeight += lineMaxHeight;

//把行高记录到集合中

lineHeightList.add(lineMaxHeight);

//把这一行的数据放进总容器

lineList.add(viewList);

//把一行的容器,重新创建一个,虽然会频繁创建,但如果调用clear,会导致lineList的栈也会被清掉

viewList = new ArrayList<>();

//把每行的高宽初始化

lineCountWidth = childWidth;

lineMaxHeight = childHeight;

viewList.add(childView);

} else {

//不需要换行的情况

lineCountWidth += childWidth;

//取当前行的所有子控件最大的高度

lineMaxHeight = Math.max(lineMaxHeight, childHeight);

viewList.add(childView);

}

//这样做的原因是 之前的if else中 不会把最后一行的高度加进listLineHeight

// 最后一行要特殊对待 不管最后一个item是不是最后一行的第一个item

if (i == (childCount - 1)) {

//保存当前行信息

childMaxWidth = Math.max(childMaxWidth, lineCountWidth + getPaddingLeft() + getPaddingRight());

childCountHeight += lineMaxHeight;

lineHeightList.add(lineMaxHeight);

lineList.add(viewList);

}

}

}

//设置控件最终大小

int measureWidth = (widthMode == MeasureSpec.EXACTLY ? widthSize : childMaxWidth + getPaddingLeft() + getPaddingRight());

int measureHeight = (heightMode == MeasureSpec.EXACTLY ? heightSize : childCountHeight + getPaddingTop() + getPaddingBottom());

setMeasuredDimension(measureWidth, measureHeight);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

//摆放子控件的位置

int left, top, right, bottom;

//保存上一个控件的边距

int countLeft = 0;

//保存上一行的高度的边距

int countTop = 0;

//遍历所有行

for (List views : lineList) {

//遍历每一行的控件

for (View view : views) {

MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();

left = countLeft + layoutParams.leftMargin;

top = countTop + layoutParams.topMargin;

right = left + view.getMeasuredWidth();

bottom = top + view.getMeasuredHeight();

view.layout(left + getPaddingLeft(), top + getPaddingTop(), right + getPaddingRight(), bottom + getPaddingBottom());

//记录当前控件的实际宽度坐标,让下一个控件知道X轴的起点在哪

countLeft += view.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;

}

int i = lineList.indexOf(views);

//换行时从最左边开始

countLeft = 0;

//换行时累加高度

countTop += lineHeightList.get(i);

}

//布局结束后清空记录的list

lineList.clear();

lineHeightList.clear();

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值