之前分享了很多面試題,蠻多都自帶正確答案,來幾期易錯系列,大家一起醒醒神。
今天來個簡單的開胃一下。
這個知識點,我定義爲在面試過程中**答對不加分,答錯扣分的題目,**不過在我以前面試經歷中,能完整說上來的同學不多。
我們一起來看看大家對這個知識的掌握程度吧。
在早期的博客的裏面,很多時候,見到有如下的介紹:
- 如果你的
View
設置了match_parent
,則在onMeasure
中得到的測量模式爲:EXACTLY
; - 如果設置了
wrap_conent
,則對應測量模式爲:AT_MOST
; - 還剩下一個
UNSPECIFIED
大家不用管,不常用;
上述描述每句話都可以認爲是錯的。
那麼今天我要搞清楚幾個問題:
match_parent / wrap_conent
一定對應EXACTLY/ AT_MOST
嗎 ?- 測量模式到底是由哪些因素確定的?
UNSPECIFIED
真的不常見嗎?
1. match_parent和wrap_content
就一定對應MeasureSpec.EXACTLY
和MeasureSpec.AT_MOST
嗎?
肯定不是。
爲什麼呢?
因爲View
在measure
時,它的寬高MeasureSpec
完全是取決於父容器,父容器傳的是什麼它收到的就是什麼。
如果這個父容器的onMeasure
方法裏面寫死了每個子View
的MeasureSpec
的Mode
爲UNSPECIFIED
的話,那麼無論你在xml
佈局或者LayoutParams
中怎麼設置寬高都好,最終子View
的onMeasure
收到的也是UNSPECIFIED
。
好吧,故意手動指定的不算。
就以正常的角度來看:
我們都知道,自定義ViewGroup
過程中,需要在onMeasure
裏面對子View
進行測量。
在測量子View
時,往往會通過measureChild
、measureChildWithMargins
方法來完成(比如FrameLayout
、LinearLayout
、CoordinatorLayout
、ViewPager2
)。
或者調用ViewGroup
的靜態方法getChildMeasureSpec
來直接獲取目標子View
的MeasureSpec
,然後手動measure
(比如ScrollView
、NestedScrollView
、DrawerLayout
、TabLayout
、ConstraintLayout
)。
其實,measureChild
和measureChildWithMargins
裏面也是會通過getChildMeasureSpec
方法來獲取MeasureSpec
的,也就是說,上面提到的這些容器,在測量它們的子View
之前,都是先通過getChildMeasureSpec
方法來獲取子View
的寬高MeasureSpec
,然後傳給子View
的measure
方法的。
好,那我們現在來看看getChildMeasureSpec
方法裏面做了什麼:
public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
int specMode = MeasureSpec.getMode(spec);
......
switch (specMode) {
case MeasureSpec.EXACTLY:
if (childDimension >= 0) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.MATCH_PARENT) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.WRAP_CONTENT) {
......
resultMode = MeasureSpec.AT_MOST;
}
break;
case MeasureSpec.AT_MOST:
if (childDimension >= 0) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.MATCH_PARENT) {
......
resultMode = MeasureSpec.AT_MOST;
} else if (childDimension == ViewGroup.LayoutParams.WRAP_CONTENT) {
......
resultMode = MeasureSpec.AT_MOST;
}
break;
case MeasureSpec.UNSPECIFIED:
if (childDimension >= 0) {
......
resultMode = MeasureSpec.EXACTLY;
} else if (childDimension == ViewGroup.LayoutParams.MATCH_PARENT) {
......
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == ViewGroup.LayoutParams.WRAP_CONTENT) {
......
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
}
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
可以看到:
在**父容器的specMode爲EXACTLY
**時,一切正常(子View
尺寸指定爲match_parent
或精確的dimen
值時,Mode = EXACTLY
,尺寸指定爲wrap_content
則Mode = AT_MOST
);
當**父容器specMode爲AT_MOST
**的時候,呵呵,可以看到,除了指定了dimen
值之外,無論設置爲match_parent
或wrap_content
,Mode
最終都是會變成AT_MOST
;
如果**父容器specMode
是UNSPECIFIED
**的話,跟上面的邏輯差不多,都是會變成UNSPECIFIED
的,除非指定了精確的dimen
值;
所以,View
的onMeasure
方法中收到的寬高MeasureSpec
,不完全是由xml
佈局中設置的寬高或LayoutParams
的寬高值決定的。
2. 有哪些因素影響着MeasureSpec的mode?
從剛剛的getChildMeasureSpec方法中可以看出,影響着View測量模式的因素主要是該View所屬容器的測量模式。
也就是說,正常情況下(不是故意亂設置),View的測量模式是由:
**它自身的LayoutParams
設置的值 **+ 父容器的測量模式來決定的。
爲什麼大家都說MeasureSpec.UNSPECIFIED
不常見呢?
大家都覺得這個模式不常見,很可能就是因爲在編寫佈局時,View
的寬高只能選擇match_parent
、wrap_content
或者直接指定一個精確的尺寸,相對來說,MeasureSpec.UNSPECIFIED
就顯得不太透明瞭,因爲在日常開發中,如不需定製View
的話,基本上不會直接接觸到。
3. MeasureSpec.UNSPECIFIED是不是真的不常見?
在日常定製View
時,確實很少會專門針對這個模式去做特殊處理,大多數情況下,都會把它當成MeasureSpec.AT_MOST
一樣看待,就比如最最常用的TextView
,它在測量時也是不會區分UNSPECIFIED和AT_MOST
的。
不過,雖說這個模式比較少直接接觸到,但很多場景下,我們已經在不知不覺中用上了,比如RecyclerView
的Item
,如果Item
的寬/高是wrap_content
且列表可滾動的話,那麼Item
的寬/高的測量模式就會是UNSPECIFIED
。
還有就是NestedScrollView
和ScrollView
,因爲它們都是擴展自FrameLayout
,所以它們的子View
會測量兩次,第一次測量時,子View
的heightMeasureSpec
的模式是寫死爲UNSPECIFIED
的。
我們在自定義ViewGroup
過程中,如果允許子View
的尺寸比ViewGroup
大的話,在測量子View
時就可以把Mode
指定爲UNSPECIFIED
。
好了,希望這次你徹底弄明白了自定義控件的測量模式相關知識。
另外也有人給我發了個圖,說這個圖就能說明白了,其實這個圖也有一點點小問題:
我畫圈的地方,這個值不一定是 0, 不過大多情況下 UNSPECIFIED
這個模式一般不在乎這個size
。
最後
今天就講到這裏,我的Android核心技術學習大綱,獲取相關內容來我的GitHub一起玩耍:https://github.com/Meng997998/AndroidJX
對於進階這條路而言,學習是會有回報的!
你把你的時間投資在學習上,就意味着你可以收穫技能,更有機會增加收入。
分享我的Android學習PDF大全
這份Android學習PDF大全真的包含了方方面面了,內含Java基礎知識點、Android基礎、Android進階延伸、算法合集等等
Android學習PDF大全關注我看個人介紹,或者私信我獲取
我的這份學習合集,可以有效的幫助大家掌握知識點。
總之也是在這裏幫助大家學習提升進階,也節省大家在網上搜索資料的時間來學習,也可以分享給身邊好友一起學習