android自定义view总结2

今天倒腾一了一下自定义直接继承自ViewGroup的自定义容器,结果什么也没倒腾出来,不过导师收获到了不少,在这里总结一下,怕到时候忘掉了。


1.我们都知道ViewGroup中的LayoutParams是不带有Margin值的,所以刚开始的时候想着继承自ViewGroup.LayoutParams写一个LayoutParams,把改加的都加上,但是这里产生了一个误区,我一直认为LayoutParams这个类是给自己调用的,然后获取自己的Margin值设置进去;但是翻看了一遍ViewGroup和LinearLayout的源码,发现并没有在类中的成员变量存有LayoutParams的引用,却是在addView()方法中调用了LayoutParams的构造方法;联想到项目中经常发生的LayoutParams强转错误的案例,搞懂了为什么,容器类中的LayoutParams都是给子类去设置的,并不是给自己用的;

2.LinearLayout的LayoutParams继承的并不是ViewGroup.LayoutParams而是ViewGroup中的另外一个MarginLayoutParams,而MarginLayoutParams是直接继承ViewGroup.LayoutParams的,MarginLayoutParams中保存了margin值。

3.View中是没有LayoutParams的,所以TextView等View控件中的LayoutParams都是由父容器设置的,也证实了第一点,源码如下:

if (!checkLayoutParams(params)) {
            params = generateLayoutParams(params);
        }
这个是ViewGroup中的一段代码;通过这段代码将LayoutParams设置到View上去;所以我们还需要重写generateLayoutParams()这个方法,否则在自定义容器中调用child.getLayoutParams()得到的是ViewGroup.LayoutParams,不能获取到自己定义的,强转将会报错, 代码如下:

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

    @Override
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
        if (lp instanceof LayoutParams) {
            return new LayoutParams((LayoutParams) lp);
        } else if (lp instanceof MarginLayoutParams) {
            return new LayoutParams((MarginLayoutParams) lp);
        } else {
            return new LayoutParams(lp);
        }
    }

4.当自定义容器的属性为layout_width或者layout_height属性为WRAP_CONTENT时,需要自己通过setMeasureDimension(width,height)方法手动设置宽高,否则默认设置的宽高是0。

5.当容器内的子View的Layout_width或者layout_height属性为MATCH_PARENT时,需要重新测量View的宽高,否则MATCH_PARENT属性的效果无效而变为WRAP_CONTENT的效果。

onMeasure代码如下:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        List<View> list = new ArrayList<>();
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int mHeight = 0;
        int childCount = getChildCount();
        switch (heightMode) {
            case MeasureSpec.UNSPECIFIED:
                break;
            case MeasureSpec.AT_MOST:
                for (int i = 0; i < childCount; i++) {
                    View child = getChildAt(i);
                    LayoutParams params = (LayoutParams) child.getLayoutParams();
                    if (params.height == ViewGroup.LayoutParams.MATCH_PARENT){
                        list.add(child);
                    }else if (params.height == ViewGroup.LayoutParams.WRAP_CONTENT){
                        mHeight = Math.max(mHeight, child.getMeasuredHeight() + params.bottomMargin + params.topMargin);
                    }else if (params.height > 0){
                        mHeight = Math.max(mHeight, child.getMeasuredHeight() + params.bottomMargin + params.topMargin);
                    }
                }
                if (list.size() != 0){
                    int realHeightSpec;
                    for (int i = 0; i < list.size(); i++) {
                        View child = list.get(i);
                        LayoutParams params = (LayoutParams) child.getLayoutParams();
                        if (child.getMeasuredHeight() < (mHeight - params.bottomMargin - params.topMargin)){
                            realHeightSpec = MeasureSpec.makeMeasureSpec(mHeight - params.bottomMargin - params.topMargin,MeasureSpec.EXACTLY);
                            measureChild(child,widthMeasureSpec,realHeightSpec);
                        }
                    }
                }
                break;
            case MeasureSpec.EXACTLY:
                MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
                mHeight = getMeasuredHeight() + params.topMargin + params.bottomMargin;
                break;
        }
        setMeasuredDimension(getMeasuredWidth(), mHeight);
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值