在这一篇中,我们主要是来实现FlowLayout中的onLayout函数。为子View进行布局,即确定子View在ViewGroup中的位置;和onMeasure一样,将onLayout分成多个部分进行分析。
第一部分及与之相关联的变量:
// 存储所有的View
private List<List<View>> mAllViews = new ArrayList<List<View>>();
//每一行的高度
private List<Integer> mLineHeight = new ArrayList<Integer>();
每一个变量的意义在注释中都有详细的解释,mAllViews相当于一个二维的View数组.
mAllViews.clear();
mLineHeight.clear();
// 当前ViewGroup的宽度
int width = getWidth();
//每一行的宽高
int lineWidth = 0;
int lineHeight = 0;
//同一行的View放在一个List中
List<View> lineViews = new ArrayList<View>();
//总的子View个数
int cCount = getChildCount();
第二部分:计算每一行的高度和确定每一行的View for (int i = 0; i < cCount; i++)
{
View child = getChildAt(i);
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
// 如果需要换行
if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width - getPaddingLeft() - getPaddingRight())
{
// 记录LineHeight
mLineHeight.add(lineHeight);
// 记录当前行的Views
mAllViews.add(lineViews);
// 重置我们的行宽和行高
lineWidth = 0;
lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
// 重置我们的View集合
lineViews = new ArrayList<View>();
}
lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
+ lp.bottomMargin);
lineViews.add(child);
}// for end
// 处理最后一行
mLineHeight.add(lineHeight);
mAllViews.add(lineViews);
这一部分与onMeasure的第三部分相似:首先获得子View,并测量子View的宽高。根据与ViewGroup的宽来判断是否需要换行。如果需要换行的话,就将之前计算这一行的高度与子View的加到mLineHeigh与mAllViews中,并重置行宽,行高和View集合。将新View的宽加入行宽,高与行高相比较,并加入到View的行集合中。因为最后一行不会大于行宽,所以没有for中加上,那么在for结束出来的时候就要加上最后一行。
第三部分:设置子View的位置
int left = getPaddingLeft();
int top = getPaddingTop();
// 行数
int lineNum = mAllViews.size();
for (int i = 0; i < lineNum; i++)
{
// 当前行的所有的View
lineViews = mAllViews.get(i);
lineHeight = mLineHeight.get(i);
for (int j = 0; j < lineViews.size(); j++)
{
View child = lineViews.get(j);
// 判断child的状态
if (child.getVisibility() == View.GONE)
{
continue;
}
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
int lc = left + lp.leftMargin;
int tc = top + lp.topMargin;
int rc = lc + child.getMeasuredWidth();
int bc = tc + child.getMeasuredHeight();
// 为子View进行布局
child.layout(lc, tc, rc, bc);
left += child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;//也可用rc来更新
}
left = getPaddingLeft() ;
top += lineHeight ;
}
将子View一行一行的设置,即先从mAllViews中获得一行的View,将一行的子View计算依次获得上下左右四个位置,而同一行的View的top与bottom是相同的,right可以通过left来获得,而同一行中下一个子View的left始终是上一个left加上左右边距。而行与行的之间的top和bottom是由mLineHeight中获得的高度和上下边距确定下来的。