什么是流式布局?其实我们在平时遇到过,只是有可能叫不出它的名字。
如图:
如上图,就是一个流式布局的样式。
&esmp;这里,将记录一下怎么实现这个功能。其实实现这个功能的方法,就是自定义ViewGroup。
自定义ViewGroup的时候,要注意两点:
1.子View和父View大小的测量。
2.子View的在父View里面怎么摆放。
想要解决上面的两个问题,就得重写两个方法,分别是:onMeasure方法,在这个方法我们通常来测量子View和父View的大小;onLayout方法,在这个方法里面,我们通常来决定子View在父View的摆放。
1.重写onMeasure方法
//测量父控件和子控件的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = getMeasuredWidth();
int height = 0;
int lineWidth = 0;
int lineHeight = 0;
int childWidth = 0;
int childHeight = 0;
for (int i = 0, n = getChildCount(); i < n; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams();
Log.i("main", "width = " + child.getMeasuredWidth() + " height = " + child.getMeasuredHeight() + " leftMargin = " + marginLayoutParams.leftMargin + " rightMargin = " + marginLayoutParams.rightMargin);
childWidth = child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;
childHeight = child.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin;
//换行
if (lineWidth + childWidth > width) {
lineWidth = childWidth;
height += lineHeight;
} else {
lineWidth += childWidth;
lineHeight = Math.max(childHeight, lineHeight);
}
if (i == n - 1) {
height += lineHeight;
}
}
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width, heightMode == MeasureSpec.EXACTLY ? heightSize : height);
}
2.重写onLayou方法
private List<List<View>> mAllViews = new ArrayList<List<View>>();
private List<Integer> mLineHeights = new ArrayList<Integer>();
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mAllViews.clear();
mLineHeights.clear();
int width = getWidth(); // 父布局的宽度
List<View> lineViews = new ArrayList<View>();
int childWidth = 0;
int childHeight = 0;
int lineWidth = 0;
int lineHeight = 0;
Log.i("main", "childCount = " + getChildCount() + " width = " + width);
for (int i = 0, n = getChildCount(); i < n; i++) {
View child = getChildAt(i);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams();
childWidth = child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;
childHeight = child.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin;
if (childWidth + lineWidth > width) {
mAllViews.add(lineViews);
mLineHeights.add(lineHeight);
lineViews = new ArrayList<View>();
lineWidth = 0;
lineHeight = childHeight;
}
lineWidth += childWidth;
lineHeight = Math.max(lineHeight, childHeight);
lineViews.add(child);
}
mAllViews.add(lineViews);
mLineHeights.add(lineHeight);
int top = 0;
int left = 0;
Log.i("main", "n = " + mAllViews.size() + " m = " + lineViews.size());
for(int i = 0, n = mAllViews.size(); i < n; i++)
{
lineViews = mAllViews.get(i);
for(int j = 0, m = lineViews.size(); j < m; j++)
{
View child = lineViews.get(j);
if(child.getVisibility() == View.GONE)
{
continue;
}
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) child.getLayoutParams();
int lc = left + marginLayoutParams.leftMargin;
int tc = top + marginLayoutParams.topMargin;
int rc = lc + child.getMeasuredWidth();
int bc = tc + child.getMeasuredHeight();
Log.i("main", "lc = " + lc + " tc = " + tc + " rc = " + rc + " bc = " + bc);
child.layout(lc, tc, rc, bc);
left += child.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin;
}
left = 0;
top += mLineHeights.get(i);
}
}
在自定义ViewGroup的时候,一定要定义ViewGroup的LayoutParams。所以还要重写generateLayoutParams方法。
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}