onMeasure学习笔记

在学习自定义view时,对onMeasure的理解真是很困难,网上的资料说的都大从官网上摘下来的,而且说得不明不白,看起来就犯晕。
没办法,只好自己通过实例来仔细研究一下。但研究之前,必须先对这个onMeausre的方法有个大致的理解。

onMeasure(int widthMeasureSpec, int heightMeasureSpec)Called to determine the size requirements for this view and all of its children.

Parameters
widthMeasureSpec horizontal space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.
heightMeasureSpec vertical space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.
从上面的解释,我们知道:

  1. onMeasure的两个参数用于测量水平和垂直空间大小,具体怎么测量,不得而知
  2. onMeasure被调用时用来决定当前view以及所有它的子view的尺寸请求
我一直搞不清楚两个参数的实际作用,所以只能通过实例来测试一下:

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	        System.out.println(widthMeasureSpec+":"+heightMeasureSpec);
		int w = getMeasureWidth(widthMeasureSpec);  
		int h = getMeasureHeight(heightMeasureSpec);

		setMeasuredDimension(w, h);  \\必须调用此方法,否则会抛出异常
	}

	private int getMeasureHeight(int heightMeasureSpec) {
		int result = 0;
		int size = MeasureSpec.getSize(heightMeasureSpec);  \\每次调用此方法,测量用到的size会发生变化
		int mode = MeasureSpec.getMode(heightMeasureSpec);  \\根据定义的Layout_width,Layout_height,会对此值产生影响
		if (mode == MeasureSpec.EXACTLY) {
			result = size;
		} else if (mode == MeasureSpec.UNSPECIFIED) {
			result = (int) paint.measureText("") + getPaddingLeft()
					+ getPaddingRight();
		} else {
			result = Math.min(result, size);
		}
		System.out.println("Height size:" + size);  
		System.out.println("Height mode:" + mode);
		return result;
	}

	private int getMeasureWidth(int widthMeasureSpec) {
		int result = 0;
		int size = MeasureSpec.getSize(widthMeasureSpec);
		int mode = MeasureSpec.getMode(widthMeasureSpec);
		if (mode == MeasureSpec.EXACTLY) {
			result = size;
		} else if (mode == MeasureSpec.UNSPECIFIED) {
			result = (int) paint.measureText("") + getPaddingTop()
					+ getPaddingBottom();
		} else {
			result = Math.min(result, size);
		}
		System.out.println("Width size:" + size);
		System.out.println("Width mode:" + mode);
		return result;
	}
请注意,当我在布局文件中,为自定义view定义如下内容时,上面代码打印出的是:
 
而在调用onMeasure时,以match_parent为例,最先传入的 widthMeasureSpec和heightMeasureSpec值如下图:

Mode值分别代表:
AT_MOST=-2147483648 (0x80000000) The child can be as large as it wants up to the specified size.
EXACTLY=1073741824 (0x40000000)  :  The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be.
UNSPECIFIED=0 (0x00000000)The parent has not imposed any constraint on the child. It can be whatever size it wants.
通过上面的结果,我们来分析一下:

1.在测量width和height时,重复了四次。也就是说,每个view在onMeasure时,都会调用此方法4次来测量最终放置的位置和大小
2.在使用match_parent,wrap_content以及自定义大小时,Mode和size值会发生变化,说明Layout_width/height会对Mode和size产生影响
3.通过对比match_parent打印出的mode值,在一开始调用onMeasure时,传入的值分别为1073742302和1073742548,而当通过MeasureSpec.getMode计算之后,得到的值均为1073741824。我们把两个值一减,得到的结果是:480和724。好吧,我大胆的猜测,这就是它测量的方法。

以上有忽略或错漏的地方,希望指出!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,关于 Android 开关按钮的背景图和自定义控件,我可以为您提供一些学习笔记和分享。 1. Android 开关按钮背景图 在 Android 中,开关按钮的背景图可以通过 drawable 文件夹下的 xml 文件来实现。以下是一个简单的例子: ```xml <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/switch_on" android:state_checked="true"/> <item android:drawable="@drawable/switch_off"/> </selector> ``` 其中,我们使用了 selector 标签来表示按钮的状态。在 checked 为 true 时,使用 switch_on 图片作为背景图;否则使用 switch_off 图片作为背景图。 2. Android 自定义控件之开关按钮学习笔记分享 如果您想完全自定义一个开关按钮控件,以下是一些实现步骤: 1) 创建一个继承自 CompoundButton 的类,例如 SwitchButton。 2) 实现 SwitchButton 的构造函数和一些必要的属性。 ```java public class SwitchButton extends CompoundButton { public SwitchButton(Context context) { super(context); init(); } public SwitchButton(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SwitchButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 初始化一些属性 } } ``` 3) 在 init() 方法中,设置一些默认属性,例如背景图、文字等。 4) 重写 onMeasure() 方法,计算出 SwitchButton 的宽高。 ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(widthSize, heightSize); } ``` 5) 重写 onDraw() 方法,绘制 SwitchButton 的背景图和文字。 ```java @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制背景图和文字 } ``` 6) 重写 onTouchEvent() 方法,处理用户的触摸事件,例如改变 SwitchButton 的状态。 ```java @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 处理按下事件 break; case MotionEvent.ACTION_MOVE: // 处理移动事件 break; case MotionEvent.ACTION_UP: // 处理抬起事件 break; } return super.onTouchEvent(event); } ``` 7) 最后,将 SwitchButton 添加到布局文件中即可。 ```xml <com.example.myapp.SwitchButton android:id="@+id/switchButton" android:layout_width="wrap_content" android:layout_height="wrap_content"/> ``` 以上就是自定义开关按钮控件的一些步骤和注意事项。希望对您有帮助!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值