天天看點

activity調用fragment的方法_從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. LayoutInflater

    inflater

    這些語句的「頭部」是什麼?怎麼來的?
  2. inflate

    方法的「參數」是什麼意思,有什麼用?
  3. 這些語句是怎麼實作轉換 xml view 的?
  4. 我除了常見的用法還能怎麼用它

Question One:「頭部」

官方文檔

思考的First Step,問其所來

官方文檔對

LayoutInflater

的說明如下:

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

簡單的翻譯過來就是:

  1. 這玩意是用來将 xml 轉換為 view
  2. 這玩意不能直接new初始化,通過

    Activity

    SystemService

    擷取,你也可以自定義他的工廠方法
  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

轉換為

view

layout xml

對應的資源ID。第二第三個參數又什麼意思呢?我轉換成View為什麼需要它呢?

官方文檔

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

簡單翻譯:

  1. root是要轉換的 xml 将要存在的外部

    ViewGroup

  2. xml 轉換成 view 後要不要

    addView

    root

    (

    ViewGroup

    )

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

測試

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

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

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

接下來我們一個個實驗,實驗的過程為,通過

activity

getLayoutInflater()

方法擷取

inflater

對象,調用其

inflate

方法,傳遞不同的參數,将得到的

view

添加到

activity

布局的

viewgroup

中,檢視結果。

首先是布局展示,

activity

的布局隻有一個藍底的ViewGroup,而要加載的

view

也隻是一個黃色的View

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)
activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

注意我給藍底加了一句

android:paddingTop="32dp"

,黃底加了一句

android:layout_margin="4dp"

測試①

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

我們看到黃色的

view

幾乎填滿了整個

activity

view

width

height

margin

都無效,但是

viewgroup

padding

是有效的。

但是我們還不能确定是

root = null

attachToRoot = false

中哪個的原因,我們繼續測試

測試②

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

我們可以看到黃色的

view

裡面設定的

width

height

margin

還是無效的,但是

viewgroup

padding

是有效的。

通過這兩個測試,我猜測

root

的效果是控制

xml

裡關于

layoutparam

的設定是否有效,但是不是這樣還要看接下來的測試。而

viewgroup

的padding參數是不受影響的,這個也好了解,因為是ViewGroup的屬性,在onDraw方法裡處理的。

測試③

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

我們可以看到黃色的

view

裡面設定的

width

height

margin

也都有效了

也就是說,root的猜測基本是坐實了,接下來就剩

attachToRoot

還是一頭霧水了

測試④

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

Crash!出問題了,看看報錯資訊:

The specified child already has a parent. You must call removeView() on the child's parent first.

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

removeView()

啥意思,已經有個爹了?這爹是誰,他轉換的過程也就接觸到一個viewgroup啊,難道說

attachToRoot = true

的話就直接

addView()

了?試試看

測試⑤

activity調用fragment的方法_從inflate方法開始,搞懂LayoutInflater的inflate過程(上)

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

總結

  1. root

    參數将決定

    view

    layoutparam

    ,如果為null,那

    xml

    裡定義的最外層

    view

    layoutparam

    将全部無效
  2. attachToRoot

    表示是否需要一鍵

    addView()

    ,如果

    root

    為null,那這個參數将被自動忽略
下篇

繼續閱讀