onMeasure 作用
1.一般情况重写onMeasure()方法作用是为了自定义View尺寸的规则,如果你的自定义View的尺寸是根据父控件行为一致,就不需要重写onMeasure()方法
2.如果不重写onMeasure方法,那么自定义view的尺寸默认就和父控件一样大小,当然也可以在布局文件里面写死宽高,而重写该方法可以根据自己的需求设置自定义view大小
认识 onMeasure
1.onMeasure (int widthMeasureSpec, int heightMeasureSpec)是view自己的方法
2.onMeasure 方法简单的理解就是是用于测量视图的大小,主要是用来测量自己和内容的来确定宽度和高度
3.onMeasure有两个参数 ( int widthMeasureSpec, int heightMeasureSpec),该参数表示控件可获得的空间以及关于这个空间描述的元数据.
4.widthMeasureSpec和heightMeasureSpec这两个值通常情况下都是由父视图经过计算后传递给子视图的,说明父视图会在一定程度上决定子视图的大小。
认识 MeasureSpec
在测量自定义view的大小之前,我们需要认识一个类MeasureSpec,它封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求MeasureSpec由size和mode组成。
specMode一共有三种类型,如下所示:
- EXACTLY
表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,简单的说(当设置width或height为match_parent时,模式为
EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的) - AT_MOST
表示子视图最多只能是specSize中指定的大小。(当设置为wrap_content时,模式为AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸) - UNSPECIFIED
表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。
/**
* 比onDraw先执行
* <p>
* 一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。
* 一个MeasureSpec由大小和模式组成
* 它有三种模式:UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小;
* EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;
* AT_MOST(至多),子元素至多达到指定大小的值。
* <p>
* 它常用的三个函数:
* 1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)
* 2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)
* 3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int minimumWidth = getSuggestedMinimumWidth();
final int minimumHeight = getSuggestedMinimumHeight();
int width = measureWidth(minimumWidth, widthMeasureSpec);
int height = measureHeight(minimumHeight, heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int defaultWidth, int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int width;
switch (specMode) {
case MeasureSpec.AT_MOST:
//指定wrap_content时的宽度,这里的500一个替换为
//该View宽度设置为wrap_content时,View保持完整
//性的最小宽度。
width = 500 + getPaddingLeft() + getPaddingRight();
break;
case MeasureSpec.EXACTLY:
width = specSize;
break;
case MeasureSpec.UNSPECIFIED:
width = Math.max(defaultWidth, specSize);
default:
width = 500;
break;
}
return width;
}
private int measureHeight(int defaultHeight, int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int height;
switch (specMode) {
case MeasureSpec.AT_MOST:
//同measureWidth相同位置的含义
height = 800 + getPaddingTop() + getPaddingBottom();
break;
case MeasureSpec.EXACTLY:
height = specSize;
break;
case MeasureSpec.UNSPECIFIED:
height = Math.max(defaultHeight, specSize);
break;
default:
height = 800;
break;
}
return height;
}
网友评论