android自定义ViewGroup之瀑布流FlowLayout 简洁明了 支持padding和margin 100行代码搞定

FlowLayout完美解决购物类app参差不齐的标签、热门搜索等:

  • 支持padding和margin

  • 支持xml和java代码动态添加childView

  • 简洁明了100行代码


效果图

android自定义ViewGroup之瀑布流FlowLayout 简洁明了 支持padding和margin 100行代码搞定_第1张图片

核心代码

1、重写onMeasure:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取测量模式和测量父容器推荐宽高
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        MarginLayoutParams cParams;
        int width = 0;//用于保存最大宽度
        int height = 0;//用于保存最大高度,累加
        int lineWidth = 0;//当前行最大宽度,累加行宽度
        int lineHeight = 0;//当前行最大高度
        int cCount = getChildCount();

        for (int i = 0; i < cCount; i++) {
            View childView = getChildAt(i);
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);//测量childView
            cParams = (MarginLayoutParams) childView.getLayoutParams();
            int leftMargin = cParams.leftMargin;
            int rightMargin = cParams.rightMargin;
            int topMargin = cParams.topMargin;
            int bottomMargin = cParams.bottomMargin;
            int cWidth = childView.getMeasuredWidth() + leftMargin + rightMargin;
            int cHeight = childView.getMeasuredHeight() + topMargin + bottomMargin;
            if (lineWidth + cWidth > widthSize - getPaddingLeft() - getPaddingRight()) {//如果达到换行条件
                height += lineHeight;//累加高度
                lineHeight = cHeight;//开启新行
                width = Math.max(cWidth, lineWidth);//获取较大宽度
                lineWidth = cWidth;//初始化行宽
            } else {
                lineHeight = Math.max(lineHeight, cHeight);//获取当前行最大高度
                lineWidth += cWidth;//累加当前行宽度
            }
            if (i == cCount - 1) {//如果是最后一个clildView,比较width确保为最大值,累加最后一行高度
                width = Math.max(width, lineWidth);
                height += lineHeight;
            }
        }
        //最后加上父容器padding
        width += getPaddingLeft() + getPaddingRight();
        height += getPaddingTop() + getPaddingBottom();
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width, heightMode == MeasureSpec.EXACTLY ? heightSize : height);
    }

2、重写onLayout:

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        MarginLayoutParams cParams;
        int cCount = getChildCount();
        int selfWidth = getWidth();
        int height = 0;//最大高累加
        int lineWidth = 0;//每行最大宽累加
        int lineHeight = 0;//每行最大高
        for (int i = 0; i < cCount; i++) {
            View childView = getChildAt(i);
            if (childView.getVisibility() == View.GONE) {
                continue;
            }
            cParams = (MarginLayoutParams) childView.getLayoutParams();
            int leftMargin = cParams.leftMargin;
            int rightMargin = cParams.rightMargin;
            int topMargin = cParams.topMargin;
            int bottomMargin = cParams.bottomMargin;
            int cWidth = childView.getMeasuredWidth() + leftMargin + rightMargin;
            int cHeight = childView.getMeasuredHeight() + topMargin + bottomMargin;
            int cl = 0, ct = 0, cr = 0, cb = 0;//childView上左、下右2个点
            if (lineWidth + cWidth > selfWidth - getPaddingLeft() - getPaddingRight()) {//如果换行
                height += lineHeight;//累加高度
                lineHeight = cHeight;//开启新行
                lineWidth = cWidth;//重置行宽
                cl = getPaddingLeft() + leftMargin;
                ct = getPaddingTop() + height + topMargin;
                cr = getPaddingLeft() + cWidth - rightMargin;
                cb = getPaddingTop() + height + cHeight - bottomMargin;
            } else {
                lineHeight = Math.max(cHeight, lineHeight);//获取较大的行高
                lineWidth += cWidth;//累加行宽
                cl = getPaddingLeft() + lineWidth - cWidth + leftMargin;
                ct = getPaddingTop() + height + topMargin;
                cr = getPaddingLeft() + lineWidth - rightMargin;
                cb = getPaddingTop() + height + cHeight - bottomMargin;
            }
            childView.layout(cl, ct, cr, cb);
        }
    }

3、由于ViewGroup支持margin属性,必须重写generateLayoutParams和generateDefaultLayoutParams,否则会出现classcastexception错误

@Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

好了,就这么简单,代码仔细看应该都能看懂,主要是一些计算。

你可能感兴趣的:(android)