自定义View中为什么需要重写onMeasure()方法?

不实现OnMeasure()方法的时候

首先自定义一个简单的view:

public class myView extends View
{
	public myView(Context context) {
		super(context);
	}

	public myView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
}

在布局中使用:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <com.example.callbacktest.myView
        android:background="@android:color/black"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        />

</RelativeLayout>

显示为:

如果layout_width和layout_height都改成wrap_content,显示的内容还是一样的全屏。

所以可以得出结论在不重写onMeasure()方法的时候默认自定义VIew是填充满父控件的。

如果需要使用wrap_content属性(根据内容确定控件大小),必须重写该方法。

在特定的模式下执行相应的操作。

onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法的作用主要

是告诉父控件自己需要多少空间,主要的方法是setMeasuredDimension(width, height)

用于保存控件的大小,如果不调用将会报出异常。

重写后的自定义view:

package com.example.callbacktest;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;

public class myView extends View
{
	private static final int DEFUALT_WIDTH = 200;
	private static final int DEFUALT_HEIGHT = 100;
	public myView(Context context) {
		super(context);
	}

	public myView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		int width = measureDemission(DEFUALT_WIDTH,widthMeasureSpec);
		int height = measureDemission(DEFUALT_HEIGHT,heightMeasureSpec);
		setMeasuredDimension(width, height);
	}

	private int measureDemission(int defualtSize,int measureSpec) {
		int result = defualtSize;
		int mode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);
		//EXACTLY:使用母控件给出的确切的尺寸(specSize),
		//确定的大小一般是由控件写好的:layout_widht = "50dp",layout_height = "50dp"
		//或者使用的fill_parent,这两种情况都可以确定大小。
		if(mode == MeasureSpec.EXACTLY)
		{
			result = specSize;
		}
		//AT_MOST:不能超过母控件所给出的尺寸(specSize)
		//一般用于不能确定的小的时候,如wrap_content。
		else if(mode == MeasureSpec.AT_MOST)
		{
			result = Math.min(result,specSize);
		}
		//UNSPECIFIED:表示显示的控件大小没有指定。
		else if(mode == MeasureSpec.UNSPECIFIED)
		{
			result = defualtSize;
		}
		return result;
	}

}

详细请看注释,由于此自定义控件没有内容,所以此处给出了默认值的大小DEFUALT_WIDTH,和DEFUALT_HEIGHT.。

在AT_MOST模式下一般你可以根据自定义控件内容的size来代替。

这里还是对int类型的widthMeasureSpec和heightMeasureSpec不是很了解,怎么就能根据一个int类型获得mode和size呢?

时间: 2024-10-03 22:14:21

自定义View中为什么需要重写onMeasure()方法?的相关文章

Android查缺补漏(View篇)--自定义 View 中 wrap_content 无效的解决方案

自定义 View 中 wrap_content 无效的解决方案 做过自定义 View 的童鞋都会发现,直接继承 View 的自定义控件需要重写 onMeasure() 方法,并设置 wrap_content 时的自身大小,否在在布局文件中对自定义控件在设置大小时,wrap_content 将等同于 match_parent. 其实在 Android 中自带的控件中,也都对 onMeasure() 方法进行了重写,对于 wrap_content 等情况做了特殊处理,在 wrap_content 时

android之在view中内嵌浏览器的方法

我要做的一个东西是在一个页面的中间嵌入浏览器,一开始不知道从哪里开始,因为以前用的都是Textveiw或者editVeiw之类的控件,而它们并不能用来显示网页的内容,怎么办呢? 首先想到的是:是不是有一个用来显示网页的View呢,于是我就在eclipse里xml编辑器里输入<web,哈哈,果然下面有个提示是webVeiw,那么能不能用它呢?于是到网上搜一下它的资料,果然可以的,下面就开始吧. 先在xml里把webview建好,在代码里用findViewById()将其取出来.我的代码是: Web

Android view中的requestLayout和invalidate方法

Android view中的requestLayout和invalidate方法 requestLayout:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view重新调用他的onMeasure onLayout来对重新设置自己位置. 特别的当view的layoutparameter发生改变,并且它的值还没能应用到view上,这时候适合调用这个方法. invalidate:View本身调用迫使view重画

Swing自定义JScrollPane的滚动条设置,重写BasicScrollBarUI方法

Swing自定义JScrollPane的滚动条设置,重写BasicScrollBarUI方法 摘自:https://blog.csdn.net/qq_31635851/article/details/80986870 1.自定义BasicScrollBarUI类 1 import java.awt.AlphaComposite; 2 import java.awt.Color; 3 import java.awt.Dimension; 4 import java.awt.GradientPain

自定义View 中一些方法的调用时机

onFinishInflate()函数的调用时机: onFinishInflate() 当View中所有的子控件均被映射成xml后触发 onMeasure(int, int) 确定所有子元素的大小 onLayout(boolean, int, int, int, int) 当View分配所有的子元素的大小和位置时触发 onSizeChanged(int, int, int, int) 当view的大小发生变化时触发 onDraw(Canvas) view渲染内容的细节 onKeyDown(int

关于Android自定义View中的onTouchEvent(MotionEvent event)事件监听

今天做一个自定义ViewGroup,通过addView动态添加子控件,为了省事,直接在父控件里重写public boolean onTouchEvent(MotionEvent event){}方法来监听当前触碰是哪个按钮,遇到点问题,所以写下来. 首先是点击效果只有 MotionEvent.ACTION_DOWN,这个把返回改为return true;就行了 然后是 getX()和getRawX()的区别,这个这篇博文有写到 http://www.cnblogs.com/foura/artic

Android中实现Bitmap在自定义View中的放大与拖动

一:基本实现思路 基于View类实现自定义View –MyImageView类.在使用View的Activity类中完成OnTouchListener接口,实现对自定义View的触摸事件监听 放大与拖动 基于单点触控实现Bitmap对象在View上的拖动.并且检测View的边缘,防止拖动过界.基于两个点触控实现Bitmap对象在View上的放大.并且检测放大倍数.基于Matrix对象实现对Bitmap在View上放大与平移变换 Bitmap对象在View中的更新与显示 通过重载onDraw方法,

自定义view中自定义属性的用法.

有时候我们自定义的view需要用到有自己定义的属性. 首先定义自己的属性,在res/values/attrs.xml中定义,xml文件如下: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name = "myView"> <attr name = "text" format = "s

Android 自定义view中的属性,命名空间,以及tools标签

昨日看到有人在知乎上问这3个琐碎的小知识点,今天索性就整理了一下,其实这些知识点并不难,但是很多开发者平时很少注意到这些, 导致的后果就是开发的时候 经常会被ide报错,开发效率很低,或者看开源代码的时候很多地方看不懂. 考虑到现在越来越多的人开发环境迁移到android studio,所以一切以android studio环境为准.和eclipse开发环境相比其实两者是差不多的, 偶有区别 主要也是android studio引入的gradle脚本造成差异. 首先来看看tools标签. 这个地