自定义View-全新定制自定义View的尺寸

前言

完全自定义View的尺寸以及布局是与之前的不一样的,我们来总结一下

全新定制自定义View的尺寸

// 跟修改已有View的尺寸不一样的是:
    // 不需要调用super.onMeasure(), 完全自己计算
    // onMeasure()中的两个参数是父View传递过来的限制
   

// 限制的分类:
    // 1 UPSPECIFIED 不限制
    // 2 AT_MOST 限制上限
    // 3 EXACTLY 限制固定值

// 全新定义自定义View尺寸的方式
    // 1 重写onMeasure(), 并计算出View的尺寸
    // 使用resolveSize()来让子View的计算结果符合父View的限制

定制Layout的内部布局

// ViewGroup的onMeasure()的重写
    // 1 调用每一个子View的measure(), 让子View自我测量
    // 2 根据子View给出的尺寸, 得到子View的位置, 并保存它们的位置
    // 3 根据子View的位置和尺寸计算出自己的尺寸, 并用setMeasuredDimension()保存

注意:子View的onMeasure()的两个参数, 是需要计算的
      开发者的要求即xml文件中layout_开头的属性和ViewGroup剩余的空间这两者结合起来计算得到的



// 可用空间的判断方法
    EXACTLY和AT_MOST的可用空间就是MeasureSpec的size值
    UNSPECIFIED的可用空间无限大
    
// 关于保存子View位置的说明
    // 不是所有的Layout都需要保存子View的位置, 比如LinearLayout就可以直接累加宽度或者高度
    // 有时候对于某些子View需要重复测量两次,比如LinearLayout的宽度是wrap_content,其中一个子View是match_parent
    // 它会先用自己的MeasureSpec来测量这个子View, 在所有子View都测量完成后, 
    LinearLayout会把所有宽度是matche_parent的子View单独拎出来,单独测量一次, 
    这次使用的mode是EXACTLY, 然后size用的是宽度最宽的那个
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int selWidthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int selWidthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        for (int i = 0; i < getChildCount(); i++) {
            View childView = getChildAt(i);
            LayoutParams lp = childView.getLayoutParams();

            switch (lp.width) {
                case MATCH_PARENT:
                    if (selWidthSpecMode == EXACTLY || selWidthSpecMode == AT_MOST) {
                        childWidthSPec = MeasureSpec.makeMeasureSpec(selWidthSpecSize - userWidth, EXACTLY);
                    } else {
                        childWidthSPec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                    }
                    break;
                case WRAP_CONTENT:
                    if (selWidthSpecMode == EXACTLY || selWidthSpecMode == AT_MOST) {
                        childWidthSPec = MeasureSpec.makeMeasureSpec(selWidthSpecSize - userWidth, AT_MOST);
                    } else {
                        childWidthSPec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                    }
                    break;
                // 如果是确定的宽度, mode为EXACTLY
                default:
                    childWidthSPec = MeasureSpec.makeMeasureSpec(lp.width, EXACTLY);
            }
        }
    }







    @Override
    protected void onLayout(boolean b, int i0, int i1, int i2, int i3) {
        for (int i = 0; i < getChildCount(); i++) {
            View childView = getChildAt(i);
            // 在父View的左上右下四个坐标
            childView.layout(childLeft[i], chlldTop[i], chlldRight[i], chlldBottom[i]);
        }
    }

总结

这一节的重点大体就是MeasureSpec的mode, onMeasure(), onLayout()

感觉这节内容好乱,等我回过头来再补充一下吧 

贴个HenCoder的链接:

自定义View-全新定义View的尺寸

自定义View-定制Layout的内部布局

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值