流式布局的实现-3-onLayout

来源:互联网 发布:手机数据自动开启 编辑:程序博客网 时间:2024/06/04 19:02

在这一篇中,我们主要是来实现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中获得的高度和上下边距确定下来的。


0 0
原创粉丝点击