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

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的绘制,达到我们需要的效果。

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

在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之前需要了解的基础知识。


相关链接:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值