简单聊聊onMeasure


  最近在学习自定义View,其中的onMeasure方法一直不是很理解,今天练习了一下,下面写一下自己的一些体会。

首先,

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
方法有两个参数,我们就先只说其中的一个,因为两个意思是差不多的,对比理解即可。widthMeasureSpec虽然看起来只是一个整型的参数,其实它封装了Mode和Size两个整型,具体的实现方法这里就不阐述,使用

int specMode =MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);

来分别获取,specSize看起来就比较好理解,那specMode又是什么意思呢,我们在XML文件中配置控件的时候会使用android:layout_width="wrap_content"或者match_parent或者fill_parent。这里的Mode就是指的这个。Mode一共有三种参数

EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

UNSPECIFIED:表示子布局想要多大就多大,很少使用

先看张图


再来我们的祖传代码

  <com.zhy.customview02.view.CustomView 
         android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"      
        zhy:image1="@drawable/lmj"
         android:padding="10dp" 
        zhy:imageScaleType1="fillXY"
        zhy:titleText1="妹子1111~"
        zhy:titleTextColor1="#ff0000"
        zhy:titleTextSize1="12sp" />
    <com.zhy.customview02.view.CustomView 
         android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"      
        android:padding="10dp" 
        zhy:image1="@drawable/lmj"
        zhy:imageScaleType1="fillXY"
        zhy:titleText1="妹子1111~"
        zhy:titleTextColor1="#ff0000"
        zhy:titleTextSize1="12sp" />


@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		/**
		 * 设置宽
		 */
		int specMode =MeasureSpec.getMode(widthMeasureSpec);
		int specSize = MeasureSpec.getSize(widthMeasureSpec);
		if(specMode == MeasureSpec.EXACTLY) //match_parent
		{
			mWidth = specSize;
			Log.e("match_parent_specSize", specSize+"");
			Log.e("match_parent_mImage.getWidth()", mImage.getWidth()+"");
		}else{
			//由图片决定宽度
			int desireByImg = getPaddingLeft()+getPaddingRight()+mImage.getWidth();
			Log.e("desireByImg", desireByImg+"");
			Log.e("getPaddingLeft", getPaddingLeft()+"");
			Log.e("getPaddingRight", getPaddingRight()+"");
			Log.e("mImage.getWidth()", mImage.getWidth()+"");
			//由字体决定宽度
			int desireByTitle = getPaddingLeft()+getPaddingRight()+mTextRect.width();
			Log.e("desireByTitle", desireByTitle+"");
			Log.e("getPaddingLeft()", getPaddingLeft()+"");
			Log.e("getPaddingRight()", getPaddingRight()+"");
			Log.e("mTextRect.width()", mTextRect.width()+"");
			if(specMode == MeasureSpec.AT_MOST)//wrap_content
			{
				int desrie = Math.max(desireByImg, desireByTitle);
				mWidth = Math.min(desrie, specSize);
			}
			//Log.e("mWidth", mWidth+"");
		}


这里的只贴了一部分的onMeasure方法,只是测量宽度的部分。我们来分析一下这段代码。
当Mode是 MeasureSpec.EXACTLY即我们xml中设置的 match_parent,当前的mWidth就直接等于specSize。这种情况比较简单,甚至可以不用重写onMeasure方法
当Mode是MeasureSpec.AT_MOST即我们xml中设置的wrap_content,我们需要手动的去测量宽和高。比如上图的d第二个例子中,可以明显的看出是match_parent的。再来说说第一个,这个设置为wrap_content,整个控件由文字和图片组成,我们先获取图片和文字谁决定需要的宽度大,然后和specSize进行比较,再去小的值,因为上面已经说过,AT_MOST:表示子布局限制在一个最大值内。


关于图片决定的宽度如何计算,在上面的图中,可以看出

int desireByImg = getPaddingLeft()+getPaddingRight()+mImage.getWidth();

padding就是指内边距,是控件边缘和内容之间的距离。这个算出来的desireByImg就是图片决定的整个宽度大小。


在我们测量完宽高之后还要调用

setMeasuredDimension(mWidth, mHight);


完成整个onMeasure方法之后,我们就可以在onDraw方法中进行View的绘制,使用getMeasuredWidth()和getMeasuredHeight()方法来获取控件的宽和高,如果之前没有重写onMeasure方法,会抛出异常。


对于什么时候需要重写onMeasure方法,如果自定义的CustomView采用默认的onMeasure函数,行为如下:

(1) CustomView设置为 match_parent 或者 wrap_content 没有任何区别,其显示大小由父控件决定,它会填充满整个父控件的空间。

(2) CustomView设置为固定的值,则其显示大小为该设定的值。

如果你的自定义控件的大小计算就是跟系统默认的行为一致的话,那么你就不需要重写onMeasure函数了。

最后在顺便提一下实现这例子的过程中遇到的一下问题

canvas.drawText (String text, float x, float y, Paint paint);

这个方法中的x和y参数,x比较好理解,就是文字绘制的起始位置,但是Y就比较复杂,它是整个文字的baseline在屏幕上的位置.盗张图片

关于文字的绘制以后有时候再好好学习一下


参考文章http://blog.csdn.net/lmj623565791/article/details/24252901

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值