- // 父容器传过来的宽度方向上的模式
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- // 父容器传过来的高度方向上的模式
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- // 父容器传过来的宽度的值
- int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft()
- - getPaddingRight();
- // 父容器传过来的高度的值
- int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingLeft()
- - getPaddingRight();
- if (widthMode == MeasureSpec.EXACTLY
- && heightMode != MeasureSpec.EXACTLY && ratio != 0.0f) {
- // 判断条件为,宽度模式为Exactly,也就是填充父窗体或者是指定宽度;
- // 且高度模式不是Exaclty,代表设置的既不是fill_parent也不是具体的值,于是需要具体测量
- // 且图片的宽高比已经赋值完毕,不再是0.0f
- // 表示宽度确定,要测量高度
- height = (int) (width / ratio + 0.5f);
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
- MeasureSpec.EXACTLY);
- } else if (widthMode != MeasureSpec.EXACTLY
- && heightMode == MeasureSpec.EXACTLY && ratio != 0.0f) {
- // 判断条件跟上面的相反,宽度方向和高度方向的条件互换
- // 表示高度确定,要测量宽度
- width = (int) (height * ratio + 0.5f);
- widthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
- MeasureSpec.EXACTLY);
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
对于onMeasure方法,有几点需要注意的:
1、父容器传过来的两个参数widthMeasureSpec和heightMeasureSpec,通过MeasureSpec.getMode()来获取参数中的模式,与控件的填充方式都是有对应关系的,这在上一篇博文:Android自定义控件系列七:详解onMeasure()方法中如何测量一个控件尺寸(一)中也有提到过
①xml布局文件中的fill_parent或具体值,或者是直接设置控件的LayoutParams中的width和height的具体值或者LayoutParams.FILL_PARENT填充父容器方式,都会对应让上面通过getMode获取参数中的模式为:MeasureSpect.EXACTLY,代表精确取值,因为除了直接指定值之外,填充父容器,也是精确值
②xml布局文件中设置wrap_content方式或者是在代码中设置LayoutParams.WRAP_CONTENT方式,都会让getMode变成MeasureSpect.AT_MOST
2、对于父容器传过来的高度或者宽度的值,不一定就是控件想要的宽度或者高度的值,这是因为模式不一样,这个值代表的意义也不一样,所以才会需要通过测量来改变高度或者宽度的值来达到想要的效果。
其中,如果是模式是EXACTLY,那么传过来的值就是具体指,也可以说是父容器想要我们的控件变成这个具体的大小。
但是模式如果是AT_MOST,那么传过来的值,就不会是具体的值,一般会是一个最大值,因为AT_MOST代表,不超过多少,那么这个值就是不超过的上限。
3、可以看到我们通过拿到父容器传过来的高度,宽度的模式和值,然后经过两种if-else判断来重新测量值的大小,这两种判断的依据就是:
①当宽度确定时(宽度为EXACTLY),高度模式不是EXACTLY时(也即高度不确定时),高度按照ratio的比例来重新测量
②当高度确定时(高度为EXACTLY),高度模式不是EXACTLY时(也即高度不确定时),宽度按照ratio的比例来重新测量
4、在测量完毕之后,因为已经得到了想要的宽度或者高度的具体的精确的值,我们再通过MeasureSpec.makeMeasureSpec()方法来调用精确的值和精确的模式,来合成一个宽度/高度方向上的合成值,最后将合成好的值传递给super.onMeasure(widthMeasureSpec, heightMeasureSpec);设置控件为我们想要的大小。
然后我们就可以在XML布局文件中,将之前的ImageView改成:com.example.imageviewdemo.SmartImageView