二、自定义垂直ViewGroup如何设置margin

ViewGroup设置margin累计分为三步:
1.获取margin
2.onMeasure里面加上margin
3.onLayout布局设置margin

获取margin

首先呢,ViewGroup是自带的MarginLayoutParams的,但是在addView时,查看源码:

    public void addView(View child, int index) {
    
    
        if (child == null) {
    
    
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
    
    
            params = generateDefaultLayoutParams();
            if (params == null) {
    
    
                throw new IllegalArgumentException(
                        "generateDefaultLayoutParams() cannot return null");
            }
        }
        addView(child, index, params);
    }

然后点开generateDefaultLayoutParams,很明显,这个generateDefaultLayoutParams是不支持MarginLayoutParams的,但是我们需要获取到margin值,就需要自己来重写这个generateDefaultLayoutParams。

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

重写的generateDefaultLayoutParams,为了兼容xml和代码new出来addView.这里我们复写了所有构造。


    public static class VerticalLayoutParams extends MarginLayoutParams {
    
    

        public VerticalLayoutParams(Context c, AttributeSet attrs) {
    
    
            super(c, attrs);
        }

        public VerticalLayoutParams(int width, int height) {
    
    
            super(width, height);
        }

        public VerticalLayoutParams(LayoutParams lp) {
    
    
            super(lp);
        }
    }

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

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
    
    
        return new VerticalLayoutParams(lp);
    }

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

好了,准备工作已经做完了,接下来就可以来计算高度了,首先我们用手动的方式来计算一下总高度:

  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    
        int totalHeight = 0;
        int totalWidth = 0;
        for (int i = 0; i < getChildCount(); i++) {
    
    
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            //计算总共高度
            totalHeight = child.getMeasuredHeight() + totalHeight;
            ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
            totalHeight = totalHeight+((ViewGroup.MarginLayoutParams)layoutParams).topMargin;
            //取最大的子view的宽度
            totalWidth = Math.max(child.getMeasuredWidth(), totalWidth);
        }
        float xmlMaxWidth = getResources().getDimension(R.dimen.dp250);
        float xmlMaxHeight = getResources().getDimension(R.dimen.dp100);
        Log.d(TAG,"xmlMaxWidth = "+xmlMaxWidth+"   xmlMaxHeight = "+xmlMaxHeight+"     totalWidth = "+(totalWidth)+"  totalHeight = "+totalHeight);
        setMeasuredDimension(totalWidth,totalHeight);
    }

运行试验结果:
在这里插入图片描述
线面空出来了一部分黑色。这是因为我们的layout并未将margin这部分实现,那么接下来就来实现一下吧:

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
    
        int curTop = 0;
        for (int i = 0; i < getChildCount(); i++) {
    
    
            View child = getChildAt(i);
            VerticalLayoutParams layoutParams = (VerticalLayoutParams) child.getLayoutParams();
            curTop = curTop+layoutParams.topMargin;
            child.layout(0,curTop,child.getMeasuredWidth(),curTop+child.getMeasuredHeight());
            curTop = curTop + child.getMeasuredHeight();
        }
    }

这短代码仅仅增加了:

            VerticalLayoutParams layoutParams = (VerticalLayoutParams) child.getLayoutParams();
            curTop = curTop+layoutParams.topMargin;

获取margin并累加,看实验结果:
在这里插入图片描述已经实现了正常的margin逻辑。

猜你喜欢

转载自blog.csdn.net/aa375809600/article/details/111399736