Android读书笔记-----自定义View(1)原理

(内容来自于android开发艺术探索)

一、 ViewRoot和ViewRootImpl类

一个View的onMeasure,onDraw,onLayout过程,都是通过ViewRoot来完成的,它对应的类就是ViewRootImpl。当一个Activity创建完成后,会将DecorView(顶级View)添加到Window层中,同时会创建ViewRootImpl类和DecorView进行关联,通过performTraversals方法完成测量,布局,绘制。
DecorView:顶级view是装载setContentView的一个容器。

二、理解MeasureSpec 测量的尺寸规格


它包含两个部分 尺寸和规格(specSize和specModel)
1.specModel有三种类型
精确类型:Exactly:View的最终大小就是specSize的值,对应设置参数时,设置的具体值和match_parent。
最大类型:AT_MOST:父容器指定一个最大的值,设置值的时候不能超过这个值,对应参数warp_content。
任意类型:UNSPECIFIED
用户想设置多大就多打,不多做限制。一般不常用。

决定View大小的两个值


一个View的大小不光由MeasureSpec决定,还由LayoutParams决定。
ViewGroup的大小 由自身设定的MeasureSpec和Params(padding,margin,width/height)决定。
对于布局中的View来说,MeasureSpec由父容器传递过来,所以子View的测量规格由父容器的MeasureSpec和Params决定。

//spec:父容器的规则,padding:padding+margin,
//childDimension:子View的参数 childView.width。。。
 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);//父容器的剩余空间
         //子View的最后宽高
        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

三、onMeasure的典型逻辑

onMeasure{
 int specModel=MeasureSpec.getModel(measureSpec);
specSize=MeasureSpec.getModel(measureSpec);
 switch(specModel){
    case:MeasureSpec.AT_MOST:
     //
     breakcase:MeausreSpec.EXACTLY:
    //
    break;

 }
}

1.直接继承View需要重现onMeasure方法,并且设置
warp_content时候的大小,否则在布局中使用时相当于match_parent
2.继承ViewGroup时getMeasureWidth/heigth
是测量的宽高,不够准确,如果想要得到准确的宽高,要在onLayout中获得。

如何在activity启动时同时获得View的宽高
1.在onWindowFocusChanged:这个方法代表View已经初始化完毕了

 public void onWindowFocusChanged(boolean hasFocus){
  if(hasFocus){
     int width=view.getMeasuredWidth();
     。。。。。。
  }
}

2.view.post(runnable):还没有看懂- -。。。。

protect void onStarted(){
  super.onStart();
  view.post(new Runnable){
     public void run(){
     int width=view.getMeasureWidth();
     int height=view.getMeasureHeigth();
}
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值