流式布局的实现-3-onLayout

本文详细解析了FlowLayout中的onLayout函数实现过程,包括初始化变量、计算每一行的高度和确定每一行的View,以及设置子View的位置等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值