自定义实现FlawLayout

本文介绍了一种自定义的FlawLayout实现方法,能够自动调整子View的位置以适应不同长度的文字显示。通过遍历子View并计算每行的高度和宽度,确保布局美观且高效。

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

更新最新完成的一个自定义view!看了一遍鸿洋大神的文章,然后自己根据自己的理解实现了一个属于自己的FlawLayout!
先上一张效果的截图!
这里写图片描述

这里已经测试了超长文字的显示,没有问题,可以正常使用!
实现的逻辑:
首先,确定自己需要哪些数据;
1.每行的高度(用于确定该行的底部坐标,layout子view的时候以此为参考确定位置,同时如果设置为wrap_content的时候也需要用到,总高度即是所有行高的和)
2.每行的宽度(如果设置FlawLayout为wrap_content时候需要自己计算出view的宽度,而FlawLayout的宽度就是每一行宽度的最大值)
3.每个view的l t r b 坐标 (用于给子view定位)

计算逻辑:
1.遍历该FlawLayout内所有的view,依次取出子view在当前行试放
2.如果已占有的宽度加上当前子view的宽度小于FlawLayout给的最大宽度,则当前子view应当放在该行,然后更新该行的高度和宽度
3.如果该行已占有的宽度加上当前子view的宽度后大于FlawLayout给的最大宽度,则当前子view应当放在下一行,更新整个FlawLayout宽度和高度
4.最后注意一点,如果当前子view是最后一个,应该要”强制”换行,其实就是要再次更新整个FlawLayout的高度和宽度

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int childCount = getChildCount();// 获取子view的个数
        int lineWidth = 0;// 用于记录当前行已有的宽度
        int lineHeight = 0;// 用于记录当前行现在高度(高度取的是当前行中最高子view的高度)
        int totalWidth = 0;// 用于记录当前之前的行宽的最大值(例如:当前是行3,totalWidth是行1的宽度和行2宽度的最大值)
        int totalHeight = 0;// 用于记录当前行之前的行高的总和(例如:当前是行3,totalHeight是行1的高度 +
                            // 行2高度)

        List<MyView> currentList = null;
        currentList = new ArrayList<MyView>();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            child.setOnClickListener(this);
            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            int childWidth = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
            int childHeight = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
            if (lineWidth + childWidth <= widthSize) {//计算当前view可以被放在当前行
                currentList.add(new MyView(child, i, lineWidth));//将当前view加入到currentList中进行记录
                lineWidth += childWidth;//更新当前行已经被占用的宽度(也是如果放下一个view的起始位置)
                lineHeight = Math.max(lineHeight, childHeight);//更新当前行的高度
            } else {// 当前view在当前行放不下,需要换行.换入新的一行
                //下面四行其实还是在做上一行的数据更新工作
                totalWidth = Math.max(totalWidth, lineWidth);//换行了,说明上一行完成测量工作,更新整个ViewGroup的宽度
                totalHeight += lineHeight;//更新已有行的总高度
                children.add(currentList);//将上一行中所有的view的集合currentList加入到children中
                lineHeights.add(new Integer(totalHeight));//记录上一行底部其实位置

                //下面的数据是当前行的数据
                lineWidth = childWidth;//更新当前行已有的宽度
                lineHeight = childHeight;//更新当前行的高度
                currentList = new ArrayList<>();//新建一个新的currentList用于记录当前行的所有view
                currentList.add(new MyView(child, i, 0));//将当前view加入到currentList中
            }

            if (i == childCount - 1) {//如果是最后一个子view,不会因为放置不下被强制换行,所以要手动"换行",记录关于该行的行信息
                totalWidth = Math.max(totalWidth, lineWidth);
                totalHeight += lineHeight;
                children.add(currentList);
                lineHeights.add(new Integer(totalHeight));
            }

        }
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : totalWidth, heightMode == MeasureSpec.EXACTLY ? heightSize : totalHeight);
    }

以上就是在onmeasure中的计算过程!
处理完计算过程基本上就完成了整个FlawLayout了!再者就是去布局子view了!

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        for (int i = 0; i < children.size(); i++) {
            List<MyView> list = children.get(i);
            int size = list.size();
            for (int j = 0; j < size; j++) {
                MyView myView = list.get(j);
                View child = myView.view;
                LayoutParams params = (LayoutParams) child.getLayoutParams();
                int measuredHeight = child.getMeasuredHeight();
                int measuredWidth = child.getMeasuredWidth();
                child.layout(myView.leftLength + params.leftMargin, lineHeights.get(i) - measuredHeight - params.bottomMargin, myView.leftLength + params.leftMargin + measuredWidth, lineHeights.get(i) - params.bottomMargin);
            }
        }
    }

源码点击下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值