三行代码实现流布局

demo地址:点击打开链接

效果图:

一,先讲怎么用:

第一行.设置flowLayoutpadding和条目之间的距离
flowLayout.setPaddingAndSpacing(padding, hPadding, vPadding);
 第二行.设置textview监听,这里用来自定义每个Textview
flowLayout.setmTextViewListener();
//第三行.添加数据给流布局
flowLayout.setDataToFlowLayout(arr);
OK啦!(其实要看demo啦)

二,再讲具体如何实现的

1.将每一行的数据封装Line对象(这样比较方便操作每行的子View和行的宽高)

class Line {
        private ArrayList<View> viewList;//用来存放当前行所有的子View
        private int width;//表示所有子View的宽+水平间距
        private int height;//行的高度

        public Line() {
            viewList = new ArrayList<View>();
        }

        /**
         * 记录子VIew
         * @param child
         */
        public void addLineView(View child) {
            if (!viewList.contains(child)) {
                viewList.add(child);

                //1.更新Line的width
                if (viewList.size() == 1) {
                    //说明添加的是第一个子View,那么line的宽就是子view的宽度
                    width = child.getMeasuredWidth();
                } else {
                    //如果添加的不是第一个子View,那么应该加等于水平间距和子VIew的宽度
                    width += child.getMeasuredWidth() + horizontalSpacing;
                }
                //2.更新line的height
                height = Math.max(height, child.getMeasuredHeight());
            }
        }

        /**
         * 获取当前行的宽度
         */
        public int getLineWidth() {
            return width;
        }

        /**
         * 获取当前行的高度
         */
        public int getLineHeight() {
            return height;
        }

        /**
         * 获取当前行的所有的子View
         */
        public ArrayList<View> getViewList() {
            return viewList;
        }
    }

2.摆放所有的子view

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        for (int i = 0; i < lineList.size(); i++) {
            Line line = lineList.get(i);//获取Line对象

            //从第二行开始,每行的top总是比上一行的top多一个行高和垂直间距
            if (i > 0) {
                paddingTop += verticalSpacing + lineList.get(i - 1).getLineHeight();
            }

            ArrayList<View> viewList = line.getViewList();//获取line的view的集合

            //1.获取每行的留白的宽度
            int remainSpacing = getLineRemainSpacing(line);
            //2.计算每个view平均得到的值
            float perSpacing = remainSpacing / viewList.size();

            for (int j = 0; j < viewList.size(); j++) {
                View childView = viewList.get(j);
                //3.将得到的perSpacing增加到view的宽度上面
                int widthSpec = MeasureSpec.makeMeasureSpec((int) (childView.getMeasuredWidth() + perSpacing), MeasureSpec.EXACTLY);
                childView.measure(widthSpec, 0);

                if (j == 0) {
                    //如果是每行的第一行,name直接靠左边摆放
                    childView.layout(paddingLeft, paddingTop, paddingLeft + childView.getMeasuredWidth(),
                            paddingTop + childView.getMeasuredHeight());
                } else {
                    //如果不是第一个,需要参考前一个view的right
                    View preView = viewList.get(j - 1);
                    //当前view的left是前一个view的right+水平间距
                    int left = preView.getRight() + horizontalSpacing;
                    childView.layout(left, preView.getTop(), left + childView.getMeasuredWidth(), preView.getBottom());
                }
            }
        }
    }

3.分行:遍历所有的子View,判断哪个子View在同一行

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //*****放在测量方法里面每次测量都会初始化,清除不必要的高度*******
        lineList = new ArrayList<>();

        //1.获取FlowLayout的宽度
        int width = MeasureSpec.getSize(widthMeasureSpec);
        //2.获取用于实际比较的宽度,就是除去2边的padding的宽度
        int noPaddingWidth = width - getPaddingLeft() - getPaddingRight();

        //3.遍历所有的子View,拿子View的宽和noPaddingWidth进行比较
        Line line = new Line();//准备Line对象
        for (int i = 0; i < getChildCount(); i++) {
            View childView = getChildAt(i);
            childView.measure(0, 0);//保证能够获取到宽高

            //4.如果当前line中木有子View,则不用比较直接放入line中,因为要保证每行至少有一个子View;
            if (line.getViewList().size() == 0) {
                line.addLineView(childView);//直接存入
            } else if (line.getLineWidth() + horizontalSpacing + childView.getMeasuredWidth() > noPaddingWidth) {
                //5.如果当前line的宽+水平间距+子View的宽大于noPaddingWidth,则child需要换行
                //需要先存放好之前的line对象,否则会造成丢失
                lineList.add(line);

                line = new Line();//创建新的Line,
                line.addLineView(childView);//将当前child放入新的行中
            } else {
                //6.说明当前child应该放入当前Line中
                line.addLineView(childView);
            }

            //7.如果当前child是最后的子View,那么需要保存最后的line对象
            if (i == (getChildCount() - 1)) {
                lineList.add(line);//保存最后的Line
            }
        }

        //for循环结束了,lineList存放了所有的Line,而每个Line又记录了自己行所有的VIew;
        //计算FLowLayout需要的高度
        int height = getPaddingTop() + getPaddingTop();//先计算上下的padding值
        for (int i = 0; i < lineList.size(); i++) {
            height += lineList.get(i).getLineHeight();//再加上所有行的高度
        }
        height += (lineList.size() - 1) * verticalSpacing;//最后加上所有的行间距

        //设置当前控件的宽高,或者向父VIew申请宽高
        setMeasuredDimension(width, height);
    }

4.再通过暴露的方法添加子View就可用画出炫酷的流布局啦


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值