標籤:

從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

從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 對象。然而僅僅是根據模板,按照固定的"規律"去修改某些參數來實現目標,只能叫做是「使用」而已

那麼,我們就來將它「分解」成明確的「問題」,來具體的「學習」吧

  1. LayoutInflaterinflater 這些語句的「頭部」是什麼?怎麼來的?
  2. inflate 方法的「參數」是什麼意思,有什麼用?
  3. 這些語句是怎麼實現轉換 xmlview 的?
  4. 我除了常見的用法還能怎麼用它

Question One:「頭部」

官方文檔

思考的First Step,問其所來

官方文檔對LayoutInflater的說明如下:

簡單的翻譯過來就是:

  1. 這玩意是用來將 xml 轉換為 view
  2. 這玩意不能直接new初始化,通過ActivitySystemService獲取,你也可以自定義他的工廠方法
  3. 因為性能問題,他只能把寫在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 轉換為 viewlayout xml 對應的資源ID。第二第三個參數又什麼意思呢?我轉換成View為什麼需要它呢?

官方文檔

簡單翻譯:

  1. root是要轉換的 xml 將要存在的外部ViewGroup
  2. xml 轉換成 view 後要不要 addViewroot ( ViewGroup )

這是個啥意思呢,看了之後似懂非懂,我還是一臉懵逼。

測試

紙上學來終覺淺,只是看文檔還是不行,不如自己上手試試,把自己腦子裡的可能性都弄出來試試看效果,跑出來啥樣就是啥樣了。

按排列組合來說,我們一共有四種(如果你想到更多可能性,不妨自己寫出來跑跑看)

  1. root = null, attachToRoot = false
  2. root = null, attachToRoot = true
  3. root = viewgroup, attachToRoot = false
  4. root = viewgroup, attachToRoot = true

接下來我們一個個實驗,實驗的過程為,通過activitygetLayoutInflater()方法獲取inflater對象,調用其inflate方法,傳遞不同的參數,將得到的view添加到activity布局的viewgroup中,查看結果。

首先是布局展示,activity的布局只有一個藍底的ViewGroup,而要載入的view也只是一個黃色的View

注意我給藍底加了一句android:paddingTop="32dp",黃底加了一句android:layout_margin="4dp"

測試①

我們看到黃色的view幾乎填滿了整個activityviewwidthheightmargin都無效,但是viewgrouppadding是有效的。

但是我們還不能確定是root = nullattachToRoot = false中哪個的原因,我們繼續測試

測試②

我們可以看到黃色的view裡面設置的width height margin還是無效的,但是viewgrouppadding是有效的。

通過這兩個測試,我猜測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 childs parent first.

這娃兒已經有個爹了,你要當他爹得先讓他現在的爹removeView()

啥意思,已經有個爹了?這爹是誰,他轉換的過程也就接觸到一個viewgroup啊,難道說attachToRoot = true的話就直接addView()了?試試看

測試⑤

果然和我們想的一樣……那麼,可以總結一下了

總結

  1. root參數將決定viewlayoutparam,如果為null,那xml里定義的最外層viewlayoutparam將全部無效
  2. attachToRoot表示是否需要一鍵addView(),如果root為null,那這個參數將被自動忽略

下篇

推薦閱讀:

TAG:Android開發 |