今天读了简书作者[milter]的一篇文章《教你步步为营掌握自定义View》,大有裨益。作者以幽默风趣、通俗易懂的大白话一步步讲述了View的来龙去脉,甚是详尽,实属自定义View文集中的一篇非常优秀的文章。于是,深度了三遍。这种好文,当然不会忘了推荐给你们,大家赶紧学习吧。
当然,我在阅读的过程中也遇到了一些模糊不清的地方,经过一番查阅,终于弄清楚了,这里记录一下,如果恰好你也有这般疑惑,那刚好可以助你一臂之力。为了本文的通畅,我将原文整理成图片的形式,搁置于此,方便大家看我讲述的几个疑惑点时能够很方便地就地参考。图文需要点击放大,便于查看,当然,推荐你们点击文末[阅读原文],查看作者简书博客。
01 MeasureSpec
onMeasure方法中的MeasureSpec参数,分别代表了View宽和高的Size和Mode值,而这个Size就是View的Parent根据Mode分配给View的大小,所以理解这个Mode特别重要,这里我们就来说说这个Mode取值:
-
MeasureSpec.EXACTLY 准确值,具有强制性。也就是View所在的ViewGroup给它设置了一个精确值大小,常见有两种定义Mode会出现这个值:View的layout_width和layout_height属性设为match_parent,另一种就是宽高设为具体的数值,比如100dp;
-
MeasureSpec.AT_MOST最大值,具有限制性。在View的width和height属性设为wrap_content时,Mode会出现这个值。即表示,View的宽高值只能在0和一个最大值之间,而这个最大值的取值就取决于View所在的ViewGroup。其实,View的默认实现就是将宽高属性为wrap_content表现为ViewGroup的宽高,大家可以自己尝试一下,自定义一个View,看看效果;
-
MeasureSpec.UNSPECIFIED 自适应,不限制。在这三个值中,UNSPECIFIED较难理解。它表示View的尺寸取决于实际需要的大小,不做任何上下限限制。一个常见的例子就是ScrollView。ScrollView给它的ChildView设置的Mode就是UNSPECIFIED。所以,ScrollView的高度由Child的实际需要决定,想多高就多高。
这一点,给大家两个参考链接,均来自stackoverflow,基本总结如上,大家也可以自行参考一下:
-
http://stackoverflow.com/questions/12266899/onmeasure-custom-view-explanation
-
http://stackoverflow.com/questions/16022841/when-will-measurespec-unspecified-and-measurespec-at-most-be-applied
resolveSizeAndState方法我还是第一次听说,确实孤陋寡闻了,网上介绍的确实也不多,但是看了它的实现之后,发现还是蛮好理解的。虽然查阅之后,还是没能理解个所以然,但是大致知道了它的必要性和使用方法,其实这个方法也间接性的帮助开发者在自定义View的时候做了一下判断,只是第三个参数通常只需要传递0即可。这一点也可以参考stackoverflow的一个回答:
http://stackoverflow.com/questions/13650903/whats-the-utility-of-the-third-argument-of-view-resolvesizeandstate
03 Calendar Lenient模式这一点也是新Get到的一个技巧,又孤陋寡闻了一下,这里作者milter在文章中只是提了一下,我查阅了Calendar源码,确实有这个解释,贴给大家:
Calendar has two modes for interpreting the calendar fields, lenient and non-lenient. When a Calendar is in lenient mode, it accepts a wider range of calendar field values than it produces. When a Calendar recomputes calendar field values for return by get(), all of the calendar fields are normalized. For example, a lenient GregorianCalendar interprets MONTH == JANUARY, DAY_OF_MONTH == 32 as February
写的非常明白了,Calendar有两种模式,当Calendar处于lenient模式时,lenient的中文含义是宽容、宽松,也表明了Month可能超过我们通常理解的30或者31等,Hour可能超过24,Minute可能超过60。所以,这里作者采取了这种写法,也是考虑比较周全的,以后我们自己写的时候也要注意了:
mMinutes = minute second / 60.0f;mHour = hour mMinutes / 60.0f;
基本上,这几点疑惑较大,不知道大家感受如何。不管如何,作者的这篇文章写的真是不错,强烈推荐对自定义View有所疑惑的朋友不妨参考一下,也欢迎留言讨论,可能你正在疑惑的点是我所没能发现的,那就是惊喜了,期待大家讨论。
,