Android學習“易錯” 系列:老司機都掉的坑,你進去了嗎?
之前分享了很多面試題,蠻多都自帶正確答案,來幾期易錯系列,大家一起醒醒神。
今天來個簡單的開胃一下。
這個知識點,我定義為在面試過程中 答對不加分,答錯扣分的題目,不過在我以前面試經歷中,能完整說上來的同學不多。
我們一起來看看大家對這個知識的掌握程度吧。
在早期的部落格的裡面,很多時候,見到有如下的介紹:
- 如果你的
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一起玩耍:
對於進階這條路而言,學習是會有回報的!
你把你的時間投資在學習上,就意味著你可以收穫技能,更有機會增加收入。
分享我的
Android學習PDF大全
這份Android學習PDF大全真的包含了方方面面了,內含Java基礎知識點、Android基礎、Android進階延伸、演算法合集等等
我的這份學習合集,可以有效的幫助大家掌握知識點。
總之也是在這裡幫助大家學習提升進階,也節省大家在網上搜尋資料的時間來學習,也可以分享給身邊好友一起學習
Android學習PDF大全關注我看個人介紹,或者私信我獲取
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952849/viewspace-2683658/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 你掉進過“偽敏捷”的陷阱嗎?敏捷
- Java-Integer好大一坑,一不小心就掉進去了Java
- 學習前端遇到瓶頸了?這些‘好’習慣都會毀掉你前端
- 學習Python這些面試題你都知道嗎?Python面試題
- 關於學習Python的疑問,你都清楚了嗎?Python
- 關於Python學習的方法以及技巧,你都知道嗎?Python
- 安卓易學,爬坑不易—騰訊老司機的RecyclerView區域性重新整理爬坑之路安卓View
- 接著Oracle的RMAN練習,恢復練習夠費勁的,一天都搭進去了……Oracle
- Android加固和簽名的那些坑(防掉坑技巧)Android
- 這些坑你都踩過嗎?獨立遊戲製作人自述5年血淚坑遊戲
- 避免踩坑:易盾安全老司機起底Android九大漏洞,附解決建議Android
- Android開發者必備的技能你會嗎?MVVM 最新學習心得!AndroidMVVM
- 你踩過flutter的坑嗎Flutter
- Android學習整理 - 系列Android
- 面試官帶你學Android——面試中Handler 這些必備知識點你都知道嗎?面試Android
- Python的十七個騷操作,你都學會了嗎?(上)Python
- CSS的23個垂直居中技巧,你都學會了嗎?CSS
- 一不小心,你就掉進了Spring延遲初始化的坑!Spring
- 每個人都應該學習程式設計嗎?程式設計
- 做自媒體創作,這些坑你都踩過嗎?快來避雷
- 身為初學Java的你,這些IDE的優缺點你都知道嗎?JavaIDE
- 學習筆記:Android這四個你不可不知的知識點,你都瞭解多少?筆記Android
- 你真的瞭解深度學習嗎?深度學習
- 你知道如何學習Linux嗎?Linux
- 滲透測試好學嗎?都需要學習哪些技術?
- 學習Linux,這些命令你都掌握了嗎?Linux
- 最通俗的安卓OpenGL教學系列總結——你學廢了嗎?安卓
- 你適合學習python嗎?python學習人群Python
- create table進階學習系列(八)
- create table進階學習系列(五)
- create table進階學習系列(七)
- create table進階學習系列(九)
- iOS這些小技巧你都知道嗎iOS
- [譯] 學習 JavaScript:9 個常見錯誤阻礙你進步JavaScript
- 不可以錯過的Android學習!帶你看Android Jetpack 最佳開發姿勢!AndroidJetpack
- 前端學習 node 快速入門 系列 —— 簡易版 Apache前端Apache
- Android2017 這些技術 —— 你都瞭解過嗎Android
- 老司機帶你快速上手除錯Flutter專案除錯Flutter