LayoutInflater.inflate及View.inflate一點小結----(當使用listview,recycleView時發現也有些不同)

感到內部比較複雜。先記錄一下

一:

 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 就會被忽略(因爲沒有已知的父視圖)。

示例

大家肯定遇到過在ListViewitem佈局中設置的高度沒有效果的問題。

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, nullfalse);
 
    }
 
    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);
 
}

二:在RecyclerView的數據適配器中使用,
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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>
@Override
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;
}





發佈了11 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章