?? 什么是流式布局?其實(shí)我們?cè)谄綍r(shí)遇到過(guò),只是有可能叫不出它的名字。
??如圖:

??如上圖,就是一個(gè)流式布局的樣式。
?&esmp;這里,將記錄一下怎么實(shí)現(xiàn)這個(gè)功能。其實(shí)實(shí)現(xiàn)這個(gè)功能的方法,就是自定義ViewGroup。
??自定義ViewGroup的時(shí)候,要注意兩點(diǎn):
??1.子View和父View大小的測(cè)量。
??2.子View的在父View里面怎么擺放。
??想要解決上面的兩個(gè)問(wèn)題,就得重寫(xiě)兩個(gè)方法,分別是:onMeasure方法,在這個(gè)方法我們通常來(lái)測(cè)量子View和父View的大?。籵nLayout方法,在這個(gè)方法里面,我們通常來(lái)決定子View在父View的擺放。
1.重寫(xiě)onMeasure方法
//測(cè)量父控件和子控件的大小
@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.重寫(xiě)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的時(shí)候,一定要定義ViewGroup的LayoutParams。所以還要重寫(xiě)generateLayoutParams方法。
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}