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

   自定义View之onMeasure()(一)

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

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

1、onMeasure():

先看看这个方法的参数

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

@Override
	protected 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(宽值,高值),它的作用就是告诉父容器,我的大小是多少,而以前所有的工作都是为这句代码做准备工作的。

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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值