安卓流式布局——标签墙
程序员文章站
2022-05-30 20:53:47
...
安卓标签墙也是一个常见的应用场景,所以最近学习写了一个流式布局,并学习一下自定义控件的一种方法,继承ViewGroup.
思路:
1.流式布局1行只能放下固定数量的标签,所以用一个类来标明一行的数据,这样在onLayout方法中就只需要将每一行的数据放到正确的位置上就可以了。这样的一个行的类的属性基本也可以确定了:当前行的标签集合,当前行的宽度,当前行的高度,:
class LineBean {
public List<View> items;//标签集合
public int width;//行宽
public int height;//行高
}
2.首先当然是考虑viewgroup的尺寸,这个尺寸需要根据子控件的累计宽高来计算:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//首先先获取到给定的宽高以及模式
int specModeW = MeasureSpec.getMode(widthMeasureSpec);
int specSizeW = MeasureSpec.getSize(widthMeasureSpec);
int specModeH = MeasureSpec.getMode(heightMeasureSpec);
int specSizeH = MeasureSpec.getSize(heightMeasureSpec);
int tWidth = 0;//总宽度
int tHeight=0;//总高度
mLines.clear();//行的集合
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);//先测量出孩子的尺寸
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight();
if (mLines.size() == 0) {//没有数据的时候,就添加第一行
LineBean lineBean = new LineBean();
lineBean.items = new ArrayList<>();
lineBean.width = horizontalSpace + width;
lineBean.height = height;
lineBean.items.add(child);
mLines.add(lineBean);
//总宽高初始化
tWidth = horizontalSpace + width;
tHeight=verticalSpace+height;
} else {//已经有了数据
LineBean lineBean = mLines.get(mLines.size() - 1);//就先拿到当前最后一行的数据
if (lineBean.width + width + horizontalSpace <= specSizeW) {//用当前行已经占有的宽度加上将要添加的标签的宽度和给定的viewgroup总宽度比较;说明当前行还能在添加这个childView
lineBean.items.add(child);
lineBean.width += horizontalSpace + width;
lineBean.height = Math.max(lineBean.height, height);//取最高高度作为当前行的高度
} else {//说明当前行不能在添加这个childView,那就新建一行,添加数据,就跟空数据时一样的操作
LineBean line = new LineBean();
line.items = new ArrayList<>();
line.width = horizontalSpace + width;
line.height = height;
line.items.add(child);
mLines.add(line);
tHeight+=height+verticalSpace;//这时候总高度也相应增加
}
tWidth = Math.max(lineBean.width, tWidth);//取得最大宽度值
}
}
//非精确模式下,控件的大小给出标签所需最大值
if (specModeW != MeasureSpec.EXACTLY) {
specSizeW = tWidth;
}
if (specModeH != MeasureSpec.EXACTLY) {
specSizeH = tHeight;
}
setMeasuredDimension(specSizeW, specSizeH);
}
上面已经将每一行的数据都封装好了,接下来在onLayout中只需要遍历每一行,然后将view摆放到正确的位置就好。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int topS = verticalSpace;
for (int i = 0; i < mLines.size(); i++) {
LineBean lineBean = mLines.get(i);//取行
int leftS = horizontalSpace;
for (int j = 0; j < lineBean.items.size(); j++) {
View child = lineBean.items.get(j);//取行中childView
int left = leftS;
int top = topS;
int right = leftS + child.getMeasuredWidth();
int bottom = topS + child.getMeasuredHeight();
child.layout(left, top, right, bottom);
leftS += child.getMeasuredWidth() + horizontalSpace;//将当前标签所占位置累加
}
topS += lineBean.height + verticalSpace;//一行排列好之后高度累加
}
}
上一篇: ai怎么绘制计算器使用的场景素材?
下一篇: python算法学习之基数排序实例