返回
自定义View之简版流式布局,解锁灵活布局新姿势
Android
2023-10-23 02:25:53
自定义View之简版流式布局
简版流式布局概述
流式布局是一种常用布局,它的特点是根据子View的实际大小动态摆放子View,排布方式较为灵活。目前安卓原生系统中,只有RecyclerView提供类似的功能,然而RecyclerView有一个比较致命的缺点,那就是它只能在一个方向上布局,而无法在两个方向上同时布局。本文实现的简版流式布局除了继承流式布局的特点之外,还能够在两个方向上同时布局,从而满足更为复杂的布局需求。
简版流式布局实现原理
简版流式布局的实现原理并不复杂,大致分为以下几个步骤:
1. 测量
遍历子View,父容器的MeasureSpec和子View的布局参数,测量子View。在测量过程中,记录每一个View的宽和高。
2. 布局
遍历过程中累加遍历的view的宽度值,如果宽度值大于等于父容器的宽度值,则换行。换行之后,将宽度值重置为0,并继续遍历子View,累加宽度值。
3. 绘制
根据子View的测量结果,将其绘制到画布上。
简版流式布局使用场景
简版流式布局可以用于多种场景,例如:
- 标签布局:可以根据标签的实际长度动态摆放标签,使标签布局更美观。
- 图片布局:可以根据图片的实际大小动态摆放图片,使图片布局更紧凑。
- 商品布局:可以根据商品的实际大小动态摆放商品,使商品布局更具吸引力。
简版流式布局代码实现
public class FlowLayout extends ViewGroup {
private int mLineSpacing; // 行间距
private int mColumnSpacing; // 列间距
public FlowLayout(Context context) {
super(context);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
mLineSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_lineSpacing, 0);
mColumnSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_columnSpacing, 0);
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int selfWidth = MeasureSpec.getSize(widthMeasureSpec);
int selfHeight = MeasureSpec.getSize(heightMeasureSpec);
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
int width = 0;
int height = 0;
int lineWidth = 0;
int lineHeight = 0;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
if (lineWidth + childWidth + mColumnSpacing > selfWidth - paddingLeft - paddingRight) {
width = Math.max(width, lineWidth);
height += lineHeight + mLineSpacing;
lineWidth = childWidth;
lineHeight = childHeight;
} else {
lineWidth += childWidth + mColumnSpacing;
lineHeight = Math.max(lineHeight, childHeight);
}
}
width += lineWidth;
height += lineHeight;
setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = getPaddingLeft();
int top = getPaddingTop();
int right = r - l - getPaddingRight();
int bottom = b - t - getPaddingBottom();
int lineWidth = 0;
int lineHeight = 0;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
if (lineWidth + childWidth + mColumnSpacing > right) {
top += lineHeight + mLineSpacing;
left = getPaddingLeft();
lineWidth = childWidth;
lineHeight = childHeight;
} else {
lineWidth += childWidth + mColumnSpacing;
lineHeight = Math.max(lineHeight, childHeight);
}
child.layout(left, top, left + childWidth, top + childHeight);
left += childWidth + mColumnSpacing;
}
}
}
总结
简版流式布局是一种常用布局,它的特点是根据子View的实际大小动态摆放子View,排布方式较为灵活。本文实现的简版流式布局除了继承流式布局的特点之外,还能够在两个方向上同时布局,从而满足更为复杂的布局需求。简版流式布局可以用于多种场景,例如:标签布局、图片布局、商品布局等。