感到內部比較複雜。先記錄一下
一:
LayoutInflater概述
從XML文件中實例化一個佈局成對應的View類, 它從來不會直接使用, 而是使用getLayoutInflater()或者getSystemService(String)來獲得一個對應當前context的標準LayoutInflater 實例。
例如:
1
2
3
|
LayoutInflater inflater = (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); |
如果要在自己的views
中通過LayoutInflater.Factory
來創建LayoutInflater
你可以用cloneInContext(Context)
來克隆一個當前存在的ViewFactory
然後再用setFactory(LayoutInfalter.FActory)
來設置成自己的FActory
.
起因
原來在項目中一直習慣用inflater.inflate(R.layout.layout, null)
最近卻發現會有一個黃色的警告。 十分好奇,所以決定找出原因。
我們發現inflate
方法有兩個:
-
View inflate(int resource, ViewGroup root)
-
View inflate(int resource , ViewGroup root, boolean attachToRoot) 第二個參數是指實例的佈局所要放入的根視圖。
一般我們在不需要將該佈局放入根視圖的時候都會把第二個參數傳爲null
,這樣系統就不會去進行相應的綁定操作了,不然就蹦了。 我相信很多人都會這樣理解,所以都很少用到 第二個方法, 其實這樣是錯誤的。
原因在於android:layout_xyz
屬性會在父視圖中重新計算,而你用第一個方法是說需要被添加到父視圖中,只不過你不知道添加到哪一個父視圖中, 所以你在xml
中定義的LayoutParams
就會被忽略(因爲沒有已知的父視圖)。
示例
大家肯定遇到過在ListView
的item
佈局中設置的高度沒有效果的問題。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<LinearLayout xmlns:android= " " android:layout_width= "match_parent" android:layout_height= "100dip" android:gravity= "center_vertical" android:orientation= "horizontal" > <TextView android:layout_width= "wrap_content" android:layout_height= "wrap_content" android:text= "test" /> </LinearLayout> |
1
2
3
4
5
6
7
8
9
10
11
|
public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null ) { convertView = inflate(R.layout.item_lv_test, null ); } return convertView; } |
如果用上面的代碼會發現設置100dp
是無效的。
而如果換成下面的代碼就可以了。
1
2
3
4
5
6
7
8
9
10
11
|
public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null ) { convertView = inflate(R.layout.item_lv_test, null , false ); } return convertView; } |
這裏你該會想一想爲什麼很多需要顯示View
的方法中都有ViewGroup
這個參數。
所以有些人會說在跟佈局中設置是無效的,要再嵌套一層佈局。 這樣是錯誤的,會造成佈局層級增多,影響性能。
細節
-
setContentView()
與LayoutInfalter.inflate()
的區別setContentView()
一旦調用,就會立即顯示UI
. 而LayoutInfalter.inflate()只是
把佈局轉換成對應的View
對象,不會立即顯示,只有需要的時候再顯示出來。 -
View.inflate()
方法與LayoutInflater.inflate()
的區別 直接上源碼:
1
2
3
4
5
6
7
|
public static View inflate(Context context, int resource, ViewGroup root) { LayoutInflater factory = LayoutInflater.from(context); return factory.inflate(resource, root); } |
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#6600f3f3"
>
<TextView
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/hello_world" />
</FrameLayout>
public MyViewHodlder onCreateViewHolder(ViewGroup root, int arg1) {
View view = inflater.inflate( R.layout.item_simple_textview,root, false);
//View view = inflater.inflate( R.layout.item_simple_textview,root);
/*
* 1.再該方法中應使用LayoutInflater.inflate,。如果是三個參數的,第二個參數爲root,且第三個參數爲false。
*2. 在該方法中不能使用View.inflate().
* 如果使用,設置的佈局很多就無效。而且第三個參數必須爲null。
* 打印異常爲:::: E/AndroidRuntime(28056): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
*/
//View view = View.inflate(context, R.layout.item_simple_textview,null/*new FrameLayout(context)*/);
MyViewHodlder hodlder = new MyViewHodlder(view);
return hodlder;
}