從inflate方法開始,搞懂LayoutInflater的inflate過程(上)
本來是完整一份的,結果一頁寫不下,分頁,感覺知乎顯示效果不行,來,點我部落格檢視
本文主要介紹:LayoutInflater
本文适合對象:打算搞懂LayoutInflater的inflate的開發者
本文字數:約2.5萬,閱讀時間:約2H
問題
先從表象入手
在Android開發過程中,很多地方都不可避免的使用到inflate方法,如在使用
RecycleView
的時候建構
ViewHolder
對象,給
Fragment
進行
CreateView
我們通常是
inflater.inflate(R.layout.xxx, container, false)
或者
LayoutInflater.from(parent.context).inflate(R.layout.xxx, parent, false)
來調用inflate方法的,不難發現,inflate方法的作用是将一個
xml布局檔案變成一個
view對象。然而僅僅是根據模闆,按照固定的"規律"去修改某些參數來實作目标,隻能叫做是「使用」而已
那麼,我們就來将它「分解」成明确的「問題」,來具體的「學習」吧
-
、LayoutInflater
這些語句的「頭部」是什麼?怎麼來的?inflater
-
方法的「參數」是什麼意思,有什麼用?inflate
- 這些語句是怎麼實作轉換 xml 為 view 的?
- 我除了常見的用法還能怎麼用它
Question One:「頭部」
官方文檔
思考的First Step,問其所來
官方文檔對
LayoutInflater
的說明如下:
簡單的翻譯過來就是:
- 這玩意是用來将 xml 轉換為 view 的
- 這玩意不能直接new初始化,通過
和Activity
擷取,你也可以自定義他的工廠方法SystemService
- 因為性能問題,他隻能把寫在layout裡被預處理過的 xml 轉換為 view ,不能随便找個xml檔案就讓他轉換
回歸表象
那好了,第一個問題解決了,
LayoutInflater
是一個不能直接new的類,他來管
xml轉換為
view,我們在
adapter
裡通過
LayoutInflater.from(context)
擷取執行個體,
fragment
則是直接使用了
FragmentManager
調用
Fragment.onCreateView
的時候傳過來的
inflater
對象
Question Two:「方法」
inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
方法有三個參數,第一個參數很好了解,就是前文所說的,
xml轉換為
view中
layout xml對應的資源ID。第二第三個參數又什麼意思呢?我轉換成View為什麼需要它呢?
官方文檔
簡單翻譯:
- root是要轉換的 xml 将要存在的外部
ViewGroup
- xml 轉換成 view 後要不要
到addView
(root
)ViewGroup
這是個啥意思呢,看了之後似懂非懂,我還是一臉懵逼。
測試
紙上學來終覺淺,隻是看文檔還是不行,不如自己上手試試,把自己腦子裡的可能性都弄出來試試看效果,跑出來啥樣就是啥樣了。
按排列組合來說,我們一共有四種(如果你想到更多可能性,不妨自己寫出來跑跑看)
- root = null, attachToRoot = false
- root = null, attachToRoot = true
- root = viewgroup, attachToRoot = false
- root = viewgroup, attachToRoot = true
接下來我們一個個實驗,實驗的過程為,通過
activity
的
getLayoutInflater()
方法擷取
inflater
對象,調用其
inflate
方法,傳遞不同的參數,将得到的
view
添加到
activity
布局的
viewgroup
中,檢視結果。
首先是布局展示,
activity
的布局隻有一個藍底的ViewGroup,而要加載的
view
也隻是一個黃色的View
注意我給藍底加了一句
android:paddingTop="32dp"
,黃底加了一句
android:layout_margin="4dp"
測試①
我們看到黃色的
view
幾乎填滿了整個
activity
,
view
的
width
,
height
和
margin
都無效,但是
viewgroup
的
padding
是有效的。
但是我們還不能确定是
root = null
、
attachToRoot = false
中哪個的原因,我們繼續測試
測試②
我們可以看到黃色的
view
裡面設定的
width
height
margin
還是無效的,但是
viewgroup
的
padding
是有效的。
通過這兩個測試,我猜測
root
的效果是控制
xml裡關于
layoutparam
的設定是否有效,但是不是這樣還要看接下來的測試。而
viewgroup
的padding參數是不受影響的,這個也好了解,因為是ViewGroup的屬性,在onDraw方法裡處理的。
測試③
我們可以看到黃色的
view
裡面設定的
width
height
margin
也都有效了
也就是說,root的猜測基本是坐實了,接下來就剩
attachToRoot
還是一頭霧水了
測試④
Crash!出問題了,看看報錯資訊:
The specified child already has a parent. You must call removeView() on the child's parent first.
這娃兒已經有個爹了,你要當他爹得先讓他現在的爹 removeView()
啥意思,已經有個爹了?這爹是誰,他轉換的過程也就接觸到一個viewgroup啊,難道說
attachToRoot = true
的話就直接
addView()
了?試試看
測試⑤
果然和我們想的一樣……那麼,可以總結一下了
總結
-
參數将決定root
的view
,如果為null,那layoutparam
裡定義的最外層xml
的view
将全部無效layoutparam
-
表示是否需要一鍵attachToRoot
,如果addView()
為null,那這個參數将被自動忽略root
下篇