聊一聊onMeasure

微信公众号:南京Android部落

1

今天呢,我们一起来研究下怎么盖房子。(what!?) 同学们,房价这么贵,该自己学学怎么盖房子了。 

大家是不是觉得楼主今天跑题啦,咱先别急,接着往下看。有时候我常想,很多技术的实现方式可能都来源于生活,但又高于生活。拿今天要讲的自定义View来说,其实我们在写自定义View的时候,需要去重写系统为我们设计好的一系列方法(如下所示):

1.png

onMeasure -> onLayout -> onDraw 这些方法。 

细细一琢磨和盖房子的步骤还是蛮像的。那我们今天就先聊一聊第一步onMeasure

2

盖房子的时候,我们先会确定一块地方,然后用工具量好建房子的地面范围,量好的这块地就是我们可以盖房子的范围。这个过程与我们在自定义View的onMeasure过程是类似的,都是确定一块我们接下来工作的范围。 

测量的过程中,我们不单会测量整个房子的大小,我们要综合考虑房子里面的房间格局和大小。我们会测量卧室的大小,测量客厅的大小以及测量厨房的大小等等。 

其实这个过程不总是那么顺利的,举个简单的例子:我期望有一个40平的卧室,40平的客厅,30平的厨房。

upload-ueditor-image-20181203-1543848732595029688.jpg

这么算下来总的需要110平吧,如果我们盖房子的用地能够满足,那我们可以愉快的按照这个期望值进行建造。可是有时候我们并没有那么大用地,我们只有80平的地,根本没法满足这些期望啊。

3.jpg

诶?那这房子还建不建了?建还是要建的,只不过不能完全满足期望而已嘛。我们可以有对卧室、客厅、厨房的美好生活向往嘛,但是美好生活向往的前提建立在伟大的特色社会主义的条件下的。社会主义教导我们“一切得从实际出发,实事求是!”。 

建房子我们可以使用社会主义科学理论作为指导,那么在自定义View时,又怎么去指导我们何为实际?什么又是美好向往呢?诶?!对了,正如我们构建自定义View的时候,onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法中的两个参数就是我们科学理论指导嘛,是上级(父类)带给我们的科学指示,你所有对生活的美好向往都必须在这个条件下执行。这样才不会乱套,社会才能更和谐。你看,谷歌也深谙和谐与科学发展之道吧。

3

那么话又说回来了,这个限制到底是如何去限制呢?我们还拿建房子为例。 

  • 如果你是一个土豪,根本不用考虑建房子的用地范围,方圆十里都是你的地,呵呵。你说你期望什么40平的卧室,那是事吗?我有这么多地,你想多大卧室都可以!这种模式就是超级富豪式的完全满足你的期望(无限制模式)

  • 有人的是这样的,我虽然有一块地,但是其中一部分我已经做了别的用处,现在卧室剩下30平的可用空间了,所以你的期望多少,我不关心,反正最多只能建30平卧室。(限制上限模式

  • 还有的人是这样的,你必须听父母的。你的父母要求卧室的大小必须是33.333平米,不能多也不能少。父母命不能违啊,我们只能按照33.333平米建造了。(精确模式

诶!?谷歌的工程师看到这一切,深深的吸了一口气,然后缓慢的吐出来,转身回到工位上,盯着想了很久的代码:

protected void onMeasure() {
// TODO 我该咋弄捏?
}

慢慢的嘴角露出一丝笑容,便顺手写下了:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
        getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

不错,是建房子给了他灵感,他将建房子限制的三个模式搬到了Android里面。在onMeasure中将上级(父类)的限制通过widthMeasureSpeheightMeasureSpec对宽和高的限制传到子View中,子view通过:

final int specMode = MeasureSpec.getMode(measureSpec);
final int specSize = MeasureSpec.getSize(measureSpec);

上面的方式将限制条件读取出来,其中specMode就是上级的限制模式,specSize就是上级限制的尺寸。然后在我们的自定义View中计算自己的尺寸时,将自己期望的尺寸和父类的要求限制再传入resolveSizeAndState方法中(实际不是直接调用此方法,此处省略),然后在这个方法中,如果读取到限制的的模式是:

  • MeasureSpec.UNSPECIFIED(无限制模式):测量的结果就是自己期望的尺寸

  • MeasureSpec.AT_MOST(限制上限模式):如果View的期望尺寸小于上限尺寸,使用View的期望尺寸。如果View的尺寸大于或者等于上限尺寸,使用上限尺寸作为测量的结果

  • MeasureSpec.EXACTLY(精确模式):View的尺寸直接使用上级(父类)要求的尺寸作为测量的结果

    public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
            final int specMode = MeasureSpec.getMode(measureSpec);
            final int specSize = MeasureSpec.getSize(measureSpec);
            final int result;
            switch (specMode) {
                case MeasureSpec.AT_MOST:    // 限制上限模式
                    if (specSize < size) {
                        result = specSize | MEASURED_STATE_TOO_SMALL;
                    } else {
                        result = size;
                    }
                    break;
                case MeasureSpec.EXACTLY:    // 精确模式
                    result = specSize;
                    break;
                case MeasureSpec.UNSPECIFIED:// 无限制模式
                default:
                    result = size;
            }
            return result | (childMeasuredState & MEASURED_STATE_MASK);
    }
    

做完这些测量以后呢,只需要调用setMeasureDimension将结果保存提交到国土局哦。

End

人民对美好生活的向往,与发展不平衡和不充分就这么愉快的解决了。父子兄弟之间的尺寸之争也被安排的妥妥的,整个社会一片和谐,人民安居乐业。

好了,onMeasure阶段就讲到这里了。下一节onLayout再见。拜拜~

动动小手,关注一下不迷路哦~

86e5636b-bad3-48fe-a783-85c3771d559a.jpg

文章不错,点个赞吧!

猜你喜欢

转载自blog.csdn.net/codeyanbao/article/details/84781659