首页 > 代码库 > Android读书笔记3:控件架构以及自定义控件

Android读书笔记3:控件架构以及自定义控件

安卓平台上这么多多姿多彩的控件是怎么制作出来的?有系统自定义的,也有开发者在系统的基础上进行自定义的。但是他们一定都遵循一定的规则,那就是android对于控件的架构设计。

言简意赅地说下:
1、所有的控件都有 共同的父类,要么父类是View,要么父类是ViewGroup,顾名思义,后者意思是View的群组,前者是单个控件。
有一个概念叫做控件树,即 所有的控件如果画成结构图,一定是一个树状结构图,我们activity里面用的findViewById就是按照树的深度优先遍历来查找对应的view( 从这里看来,如果xml里面写过太过复杂,有可能影响findViewById的效率)。
View一定是要在ViewGroup内部的,ViewGroup对于其内部的View进行统一调度和分配,控制整个视图效果。

如图:这是AndroidStudio里面的一个组件树,表示一个layout.xml里面所有组件的结构图。

技术分享

 

2、对于Activity的代码应该都不陌生,在onCreate方法内部,调用了setContentView之后,activity的内容就会被绘制出来。而绘制的第一步,就是测量Measure。每一个组件在创建之后,都会被分配一个矩形区域,作为它的所属区域用于绘制视图。那这个矩形区域多大,位置在哪
矩形的大小,是由View内部的一个方法:onMeasure()

技术分享

这是View:onMeasure的一段注释。大概意思是:
如果这个方法被子类重写了,那么子类就有责任确保测量过的宽高至少是view的最小宽高,具体怎么理解,请看下面的代码。

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d("MyTag", "onMeasure");
        setMeasuredDimension(myMeasure(widthMeasureSpec, 400), myMeasure(heightMeasureSpec, 100));
    }

    /**
     * 如果写自定义组件,那么这段代码基本可以作为 measure 的模板
     *
     * @param measureSpec
     * @param defaultValue
     * @return
     */
    private int myMeasure(int measureSpec, int defaultValue) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        // 精确模式.
        // 如果在xml内部,定义组件的宽/高的时候,使用的是具体的数字+单位,这种组合。
        // 那么就是精确模式,因为在xml里面明确指定了组件的宽/高。
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            //接着上面的说,如果系统指定宽/高的是wrap_content,
            // 那这个就是AT_MOST模式,在这里就必须给它指定一个默认值defaultValue,这样,就优化了代码,
            // 如果指定wrap_content,系统不知道该分配多大空间给它,于是就默认这个组件的宽/高充满父组件,这个显然不合理,很浪费资源的。
            // 所以这里指定一个默认的最大值,就算组件没有内容,系统也知道最大应该给他多少空间,不会造成浪费
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(defaultValue, specSize);//这里获得的specSize其实是父组件的size,所以要取二者之小
            }
        }
        return result;
    }

  

 

Android读书笔记3:控件架构以及自定义控件