欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

安卓流式布局——标签墙

程序员文章站 2022-05-30 20:53:47
...

安卓流式布局——标签墙安卓标签墙也是一个常见的应用场景,所以最近学习写了一个流式布局,并学习一下自定义控件的一种方法,继承ViewGroup.
思路:
1.流式布局1行只能放下固定数量的标签,所以用一个类来标明一行的数据,这样在onLayout方法中就只需要将每一行的数据放到正确的位置上就可以了。这样的一个行的类的属性基本也可以确定了:当前行的标签集合,当前行的宽度,当前行的高度,:

class LineBean {
        public List<View> items;//标签集合
        public int width;//行宽
        public int height;//行高
    }

2.首先当然是考虑viewgroup的尺寸,这个尺寸需要根据子控件的累计宽高来计算:

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //首先先获取到给定的宽高以及模式
        int specModeW = MeasureSpec.getMode(widthMeasureSpec);
        int specSizeW = MeasureSpec.getSize(widthMeasureSpec);
        int specModeH = MeasureSpec.getMode(heightMeasureSpec);
        int specSizeH = MeasureSpec.getSize(heightMeasureSpec);
        int tWidth = 0;//总宽度
        int tHeight=0;//总高度
        mLines.clear();//行的集合
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);//先测量出孩子的尺寸
            int width = child.getMeasuredWidth();
            int height = child.getMeasuredHeight();
            if (mLines.size() == 0) {//没有数据的时候,就添加第一行
                LineBean lineBean = new LineBean();
                lineBean.items = new ArrayList<>();
                lineBean.width = horizontalSpace + width;
                lineBean.height = height;
                lineBean.items.add(child);
                mLines.add(lineBean);
                //总宽高初始化
                tWidth = horizontalSpace + width;
                tHeight=verticalSpace+height;
            } else {//已经有了数据
                LineBean lineBean = mLines.get(mLines.size() - 1);//就先拿到当前最后一行的数据
                if (lineBean.width + width + horizontalSpace <= specSizeW) {//用当前行已经占有的宽度加上将要添加的标签的宽度和给定的viewgroup总宽度比较;说明当前行还能在添加这个childView
                    lineBean.items.add(child);
                    lineBean.width += horizontalSpace + width;
                    lineBean.height = Math.max(lineBean.height, height);//取最高高度作为当前行的高度
                } else {//说明当前行不能在添加这个childView,那就新建一行,添加数据,就跟空数据时一样的操作
                    LineBean line = new LineBean();
                    line.items = new ArrayList<>();
                    line.width = horizontalSpace + width;
                    line.height = height;
                    line.items.add(child);
                    mLines.add(line);
                    tHeight+=height+verticalSpace;//这时候总高度也相应增加
                }
                tWidth = Math.max(lineBean.width, tWidth);//取得最大宽度值
            }
        }
        //非精确模式下,控件的大小给出标签所需最大值
        if (specModeW != MeasureSpec.EXACTLY) {
            specSizeW = tWidth;
        }
        if (specModeH != MeasureSpec.EXACTLY) {
            specSizeH = tHeight;
        }
        setMeasuredDimension(specSizeW, specSizeH);
    }

上面已经将每一行的数据都封装好了,接下来在onLayout中只需要遍历每一行,然后将view摆放到正确的位置就好。

 @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int topS = verticalSpace;
        for (int i = 0; i < mLines.size(); i++) {
            LineBean lineBean = mLines.get(i);//取行
            int leftS = horizontalSpace;
            for (int j = 0; j < lineBean.items.size(); j++) {
                View child = lineBean.items.get(j);//取行中childView
                int left = leftS;
                int top = topS;
                int right = leftS + child.getMeasuredWidth();
                int bottom = topS + child.getMeasuredHeight();
                child.layout(left, top, right, bottom);
                leftS += child.getMeasuredWidth() + horizontalSpace;//将当前标签所占位置累加
            }
            topS += lineBean.height + verticalSpace;//一行排列好之后高度累加
        }
    }

本文借鉴于
项目下载地址:项目下载地址