安卓开发中自定义View之onMeasure(),onLayout(),onDraw()讲解(一)

来源:互联网 发布:广东11选5数据360遗漏 编辑:程序博客网 时间:2024/06/05 14:14

   自定义View之onMeasure()(一)

        在自定义View中,常常碰见onMeasure(),onLayout(),onDraw()三个方法,还有onTouchEvent(),可以构建我们想要实现的控件。

        我们知道,无论是我们自定义的View还是系统自带的View(例如button,textview),都是放在ViewGroup容器中,也就是所说的该控件的父容器(比如LinearLayout、RelativeLayout)中,那么这三个方法了就决定了以下事情:onMeasure()——测量自定义View的大小;onLayout()——放置在ViewGroup容器的具体哪个位置;onDraw()——如何绘制这个View(可以画扇形、圆、矩形、线条等等,只要你能想到就能画出来)。

1、onMeasure():

先看看这个方法的参数

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}
        两个参数widthMeasureSpec和heightMeasureSpec,从哪来了?首先我们 要知道这个方法在哪调用的?这个方法是放置View的父容器中调用的,这两个参数也是从该父容器ViewGroup中传来的,并且在这两个参数各自中分别携带两个值,分别是specMode和specSize,这两个值通过MeasureSpec类的静态方法getMode(参数)和getSize(参数),下面以一段项目中的代码分别获取了以下两个值

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int wSize=MeasureSpec.getSize(widthMeasureSpec);int wMode=MeasureSpec.getMode(widthMeasureSpec);int hSize=MeasureSpec.getSize(heightMeasureSpec);int hMode=MeasureSpec.getMode(heightMeasureSpec);if(wMode==MeasureSpec.EXACTLY){mWidth=wSize;}else {mWidth=DensityUtil.dip2px(context, 300);}if(hMode==MeasureSpec.EXACTLY){mHeight=hSize;}else {mHeight=DensityUtil.dip2px(context, 400);}System.out.println("mWidth....."+mWidth+"mHeight>>>>>"+mHeight);setMeasuredDimension(mWidth, mHeight);}

        通过查阅onMeasure()Android源码,所有View的onMeasure()的最后一行都调用了setMeasureDimension(宽值,高值),它的作用就是告诉父容器,我的大小是多少,而以前所有的工作都是为这句代码做准备工作的。

        而ViewGroup给View分配空间的条件是由specMode决定的,specMode一共有三种可能:

       一、 MeasureSpec.EXACTLY:父视图希望子视图的大小应该是specSize中指定的。什么意思了?就是说子视图的大小就是specSize指定的,上面例子中测出宽高的specSize值为多大,子视图宽高就是多大;

       二、 MeasureSpec.AT_MOST:子视图的大小最多是specSize中指定的值,也就是说不建议子视图的大小超过specSize中给定的值;

        三、MeasureSpec.UNSPECIFIED:我们可以随意指定视图的大小,这个用处很少,不了解也罢。

        经过测试,得出,在布局中,View属性设定中,Android:layout_widht="match_parent",或者Android:layout_widht="60dip",那么对应于EXACTLY,也就是子视图告诉父容器,大小是确定的;Android:layout_widht="wrap_content"对应于AT_MOST。

        通过以上这些分析,可以知道视图最终的大小由父视图,子视图以及程序员根据需要决定,良好的设计一般会根据子视图的measureSpec设置合适的布局大小。

        现在回过头来看看上面那段项目中的代码,那段代码的初衷就是如果开发者设定了自定义View的确定大小(测量出来的specMode为EXACTLY),那么按照开发者设定的测量宽高;如果开发者没有确定大小(测量出来的specMode为AT_MOST),那么宽设定为300dip,高设定为400dip,当然要转为像素,做了转化处理,最后大家看,一定调用了setMeasureDimesion(参数1,参数2),把测量的结果传进去,所以大家就不难理解上面蓝色标注的那段话了,再重复一遍——所有View的onMeasure()的最后一行都调用了setMeasureDimension(宽值,高值),它的作用就是告诉父容器,我的大小是多少,而以前所有的工作都是为这句代码做准备工作的。

        今天就写到这儿,如果大家还不理解,可以留言,只要留言肯定解决。




0 0
原创粉丝点击