對於android初學者而言,看到LayoutInflater只能說是“愛過“。在自定義控件的時候構造函數中會LayoutInflater.from(mContext).inflater(layout_id, this);還有重寫
適配器佈局會LayoutInflater.from(getContext()).inflater(layout_id, null);當時我也是隻知道這樣用,具體怎麼回事不是太清楚,今天就事論事,聊一聊LayoutInflater那些事兒。
首先我們要知道獲取LayoutInflater實例有三種方式,並且本質都是一樣的:
- LayoutInflater inflater = getLayoutInflater(); //調用Activity的getLayoutInflater()
- LayoutInflater inflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- LayoutInflater inflater = LayoutInflater.from(context);
讀過源碼的就會知道,三種最後都會執行到mContext.getSystemService()。
額,再來說說inflater方法,這個方法重載過一次,有兩種形式:
- inflater(int resource, ViewGroup root);
- inflater(int resource, ViewGroup root, boolean attachToRoot);
然而第一種方法本質是inflater(int resource, ViewGroup root, root != null);所以這兩個也是有聯繫的。
實踐出真理,寫個小demo,新建兩個佈局文件:
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#555"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="測試"
android:textColor="#abc"
android:textSize="40sp" />
</LinearLayout>
test.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="250dp"
android:layout_height="match_parent"
android:background="#478"
android:orientation="vertical">
</LinearLayout>
非常簡單的兩個佈局,然後我們在MainActivity中編寫:
View test = getLayoutInflater().inflate(R.layout.test, null);
setContentView(test);
運行程序:
發現寬和高並不是我們自己定義的250dp,是不是巧合咧,改下代碼:
View main = getLayoutInflater().inflate(R.layout.activity_main, null);
setContentView(main);
呀哈,這就奇了怪了,爲什麼有這種情況,不要急,細細道來。
網上看源碼分析的demo一搜幾個G,我就不扯了,inflater(int resource, ViewGroup root, boolean attachToRoot)三個參數的意義:
- resource:不說也知道,佈局的id
- root:該視圖的根佈局
- attachToRoot:是否將該視圖添加到根佈局中並返回
inflater的視圖寬高,只有匹配到root根佈局纔會正常計算,不信你去看源碼,反正我是信了。
只看解釋可能沒有什麼說服力,那我們再修改代碼:
View main = getLayoutInflater().inflate(R.layout.activity_main, null);
View test = getLayoutInflater().inflate(R.layout.test, (ViewGroup) main);
setContentView(test);
首先inflater一個main佈局,因爲root傳的null所以寬高並不是我們自己定義的寬高,然後inflater一個test佈局,這個佈局傳的root是main佈局,後面的attachToRoot我沒寫出來,大家都應該知道是true吧,所以會正確的加載test佈局,並把test佈局添加到main佈局中並返回。
有疑問,沒關係,我們將
View test = getLayoutInflater().inflate(R.layout.test, (ViewGroup) main);
改成
View test = getLayoutInflater().inflate(R.layout.test, (ViewGroup) main, false);
按照上面的說法這裏還是會正確加載test佈局,但並不會將test添加到main佈局中,我們再運行看看:
的確是這樣,證明了我們上述的猜測是對的。
好了,如果你一行一行地看到了這裏,相信你也明白了十之八九,好了,不知道大家有沒有遇到一個問題,在自定義adapter中listview不能正常顯示item的寬高,當初爲了這個抓破頭皮屑。。最簡單的解決方法就是在不要穿root爲空值,記得後面的參數傳false哦。
可能見解看法有偏差,虛心接受大牛們的評教。