Android群英传--自定义View详解(一)

来源:互联网 发布:kali linux 路由器 编辑:程序博客网 时间:2024/06/06 15:44

Android中的控件架构 :

概述:

Android中所有的控件都继承自View类,View为最顶层的类,然后在其之下又有ViewGroup和View两个大的分类,ViewGroup作为父控件可以包含多个View控件,并管理其所包含的View控件,通过ViewGroup,整个界面形成了一个树形结构,也就是常说的控件树。

控件树

实例:

那么具体到一个Activity中,这些控件树又是怎么体现的呢?通常情况下,我们在Activity中使用setContentView()来设置自己需要的界面,那他是怎么将我们的布局文件转换为视图的呢?其实对于每一个Activity而言,其总的View层次为下边的这张图:
Activity控件层次

对于我们而言,当我们调用setContentView()时设置的只是ContentView中的内容。在Activity中都包含一个Window对象,而Window的实现类就是PhoneView,在ContentView中所有的View点击事件都会通过WindowManagerService来进行接受,然后通过Activity对象来回调对应的OnClickListener。在代码中,当Activity中的onCreate()方法被调用之后,ActivityManagerService会调用onResume(),这时候系统才会把整个DecorView添加到PhoneWindow中,并让其显示出来。

View的测量和绘制:

之前说的都是关于整个Android中View的框架概述,接下来就是关于View具体怎么绘制到屏幕上。

View的测量:

View的具体测量是在onMeasureSpec()这个方法中完成的。同时Android中也提供给我们用于测量的辅助类MeasureSpec。MeasureSpec类是一个32位的int值,其中高两位为测量的模式,低30位是测量的大小。

View的测量模式:

  • EXACTLY:精确值模式,当我们为控件定义具体的宽高属性时,或者是沾满父控件时使用该测量模式。

  • AT_MOST:最大值模式,当控件的宽高属性为warp_content时,控件大小一般由控件中的具体内容决定,这时只要该控件不超过父控件的大小即可。

  • UNSPECIFIED:该模式不指定View大小的测量模式,通常使用自定义View时才会使用该模式。

在自定义View时需要重写View的onMeasure()方法,他默认是调用了父类中的onMeasure()方法。

父类View的方法

而父类中的onMesure()方法则是通过setMeasureDimension(),方法来设置View的尺寸。所以我们可以通过在onMeasure()重新计算View的长和宽,然后将其通过setMeasureDimension()方法来修改控件的尺寸。

在onMeasure()中,我们需要根据测量模式来进行不同的计算:

  • 当测量模式为EXACTLY时,直接使用给定的尺寸值,

  • 当测量模式为UNSPECIFIED时,需要给View一个默认的大小,

  • 当测量模式为AT_MOST时,需要将默认的大小和测量出来的最小值进行比较,取其中较小值作为结果。

/**     * 重写测量方法     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));    }    /**     * 默认的View大小     */    public static final int DEFAULT_SIZE = 200;    /**     * 自定义的测量高度的方法     * @param heightMeasureSpec     * @return     */    private int measureHeight(int heightMeasureSpec) {        return measure(heightMeasureSpec);    }    /**     * 自定义的测量宽度的方法     * @param widthMeasureSpec     * @return     */    private int measureWidth(int widthMeasureSpec) {        return measure(widthMeasureSpec);    }    /**     * 自定义的测量方法     * @param measureSpec     * @return     */    private int measure(int measureSpec) {        //获取测量模式和测量值        int specMode = MeasureSpec.getMode(measureSpec);        int specSize = MeasureSpec.getSize(measureSpec);        //最后的测量值        int size = DEFAULT_SIZE;        //根据不同的测量模式,有不同的测量结果        if (specMode == MeasureSpec.EXACTLY) {            size = specSize;        }else{            size = DEFAULT_SIZE;            if (specMode == MeasureSpec.AT_MOST) {                size = Math.min(specSize,size);            }        }        return size;    }

View的绘制:

在将View测量完之后就需要根据要求进行View的绘制,达到我们需要的效果。

关于绘制的详细讲解可以看之前的文章:

  • Android群英传–绘图机制与处理技巧(一)

  • Android群英传–绘图机制与处理技巧(二)

  • Android群英传–绘图机制与处理技巧(三)

在View中重写onDraw()方法,并在其中进行图像的绘制。

ViewGroup的测量和绘制:

ViewGroup的测量:

ViewGroup的测量和View的测量原理相似,只是需要对子View需要遍历测量。

  • 当ViewGroup设置为warp_content时,需要遍历所有的子View,从而决定自己的大小,同样需要重写ViewGroup的onMeasure()方法。

  • 当ViewGroup设置为其他具体的值时就根据具体的值来设置自己的大小。

注:在ViewGroup测量自身尺寸时,会依次调用子View的onMeasure方法来获取测量结果

ViewGroup的布局:

在测量完成之后就需要将所有的子View放在合适的位置,这时候就会通过View的onLayout()方法来为每个子控件找到合适的位置。在布局时同样是通过遍历调用子View的onLayout()方法,指定具体的显示的位置,从而决定布局位置。

ViewGroup的绘制:

ViewGroup自己的绘制任务并不是很重,若不是为其指定了背景色,其甚至不会调用自身的onDraw()方法,在该步骤中,ViewGroup最重要的方法是dispatchDraw()方法,即通过这个方法来遍历调用子View的绘制方法,从而完成绘制。

这些就是一些关于自定义View之前需要了解的基础知识。


相关链接:

  • Android群英传–绘图机制与处理技巧(一)

  • Android群英传–绘图机制与处理技巧(二)

  • Android群英传–绘图机制与处理技巧(三)

  • Android群英传–动画机制与技巧(一)

  • Android群英传–动画机制与技巧(二)

0 0
原创粉丝点击