Android-超简单的流式布局

流式布局,一般在商城类的项目中用到会非常多比如

淘宝中,购物选择商品列表的时候,这个就是流式布局

 

 创作起来也很简单,

只要你计算出宽度,和高度,如果超出屏幕宽度,则换行摆放即可

然后我就尝试着写了一下,果然还是可以的

效果图

核心方法主要是viewgroup的layout方法

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 为什么定义x,因为是从这个坐标开始出发
        // 往右进行摆放
        int x = (int) (this.getPaddingLeft() + leftMargin);

        int paddingRight = this.getPaddingRight();
        // 为什么定义y,因为从上往下,top等于y轴线
        int y        = (int) (this.getPaddingTop() + topMargin);
        int sumWidth = r - l;

        int childCount = this.getChildCount();

        int childMaxHeight = 0;
        for (int i = 0; i < childCount; i++) {
            View view = this.getChildAt(i);

            // 如果大于了。需要规整
            if (sumWidth < x + view.getMeasuredWidth() + paddingRight) {
                // 跨行
                // 改变x轴起始点
                x = (int) (getPaddingLeft() + leftMargin);
                // 改变y轴起始点
                y += childMaxHeight;
                childMaxHeight = 0;
            }
            view.layout(x, y, x + view.getMeasuredWidth(), y + view.getMeasuredHeight());
            // 改变横坐标,切记加入view的宽度.否则会出问题
            x += view.getMeasuredWidth() + rightMargin;
            // 取最大宽度,为下一步跨行做准备
            childMaxHeight = (int) Math.max(childMaxHeight, view.getMeasuredHeight() + topMargin + bottomMargin);
        }

    }

其次就是测量方法了.测量方法需要测量出总大小来控制view的大小

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 获取子view的数量
        int childCount = this.getChildCount();
        // 获取到本view的宽度最大值
        int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingLeft() - this.getPaddingRight();
        // 需要测量view的宽度以及view的高度。
        // 所有的合集
        // 总高度
        int sumHeight = 0;
        // 一行的子类总高
        int childMaxHeight = 0;
        // 总宽度
        int sumWidth = 0;
        // 一行的子类总宽
        int sumChildWidth = 0;
        for (int i = 0; i < childCount; i++) {
            View view = this.getChildAt(i);
            measureChild(view, widthMeasureSpec, heightMeasureSpec);
            // 如果有leftMargin的话,需要在测量的时候,加上这个
            sumChildWidth = (int) (sumChildWidth + leftMargin + rightMargin);
            // 如果小于两者相加,所以超了,需要计算高度
            // 取高度最大值,也就是所有控件的最大值
            // 加完之后要清除,否则下一行高度无法计算
            if (maxWidth < (sumChildWidth + view.getMeasuredWidth())) {
                // 跨行
                sumHeight += childMaxHeight;
                childMaxHeight = 0;
                // 跟自己比较,获取最大值,优先取最大
                sumWidth = Math.max(sumChildWidth, sumChildWidth);
                sumChildWidth = 0;

            }
            // 判断子类高度最大值
            childMaxHeight = (int) Math.max(childMaxHeight, view.getMeasuredHeight() + topMargin + bottomMargin);
            // 取子类行总宽,需要判断父类的宽度
            sumChildWidth += view.getMeasuredWidth();
        }
        // 因为最后一行可能没有超过,所以不会进入,则需要重新加一下最后一行
        sumHeight += childMaxHeight;
        sumWidth = Math.max(sumChildWidth, sumWidth);

        setMeasuredDimension(measureWidth(widthMeasureSpec, sumWidth), measureHeight(heightMeasureSpec, sumHeight));

    }


    private int measureHeight(int heightMeasureSpec, int sumHeight) {
        int result = 0;
        int mode   = MeasureSpec.getMode(heightMeasureSpec);
        int size   = MeasureSpec.getSize(heightMeasureSpec);
        //EXACTLY
        //精确值模式,当控件的layout_width和layout_height属性指定为具体数值或match_parent时。

        //AT_MOST
        //最大值模式,当空间的宽高设置为wrap_content时。

        //UNSPECIFIED
        //未指定模式,View想多大就多大,通常在绘制自定义View时才会用。

        // 如果为精确值模式,那么不用判断了,直接返回
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
            return result;
        }
        result = sumHeight + this.getPaddingTop() + this.getPaddingBottom();
        if (mode == MeasureSpec.AT_MOST) {
            result = Math.min(size, result);
        }
        return result;
    }

    private int measureWidth(int widthMeasureSpec, int sumWidth) {
        int result = 0;
        int mode   = MeasureSpec.getMode(widthMeasureSpec);
        int size   = MeasureSpec.getSize(widthMeasureSpec);
        // 如果为精确值模式,那么不用判断了,直接返回
        if (mode == MeasureSpec.EXACTLY) {
            result = size;
            return result;
        }
        result = widthMeasureSpec + this.getPaddingLeft() + this.getPaddingRight();
        if (mode == MeasureSpec.AT_MOST) {
            result = Math.min(size, result);
        }
        return result;
    }

演示结果就更简单了

        int[] colors = {
                Color.DKGRAY,
                Color.GRAY,
                Color.LTGRAY,
                Color.WHITE,
                Color.RED,
                Color.GREEN,
                Color.BLUE,
                Color.YELLOW,
                Color.CYAN,
                Color.MAGENTA,
                Color.TRANSPARENT
        };
        FlowLayout viewById = (FlowLayout) findViewById(R.id.fl);
        viewById.setItemMargin(10, 10, 10, 10);
        for (int i = 0; i < 1000; i++) {
            TextView textView = new TextView(MainActivity.this);
            textView.setText("我是条目 " + i);
            int i1 = new Random().nextInt(colors.length);
            textView.setBackgroundColor(colors[i1]);
            viewById.addView(textView);
        }

详细可以移步我的github

超简单的流式布局

猜你喜欢

转载自blog.csdn.net/ci250454344/article/details/84572036
今日推荐