原文:http://blog.csdn.net/andypan1314/article/details/6718298
http://blog.csdn.net/ruancoder/article/details/52090065
Inflate()作用就是將xml定義的一個佈局找出來,但僅僅是找出來而且隱藏的,沒有找到的同時並顯示功能。
android上還有一個與Inflate()類似功能的方法叫findViewById(),二者有時均可使用,但也有區別
區別在於:
如果你的Activity裏用到別的layout,比如對話框layout,你還要設置這個layout上的其他組件的內容,你就必須用inflate()方法先將對話框的layout找出來,然後再用findViewById()找到它上面的其它組件。例如:
- View view1=View.inflate(this,R.layout.dialog_layout,null);
- TextViewdialogTV=(TextView)view1.findViewById(R.id.dialog_tv);
- dialogTV.setText("abcd");
View view1=View.inflate(this,R.layout.dialog_layout,null);
TextViewdialogTV=(TextView)view1.findViewById(R.id.dialog_tv);
dialogTV.setText("abcd");
注:R.id.dialog_tv是在對話框layout上的組件,而這時若直接用this.findViewById(R.id.dialog_tv)肯定會報錯。
- View viewStub = ((ViewStub) findViewById(R.id.stubView)).inflate();
View viewStub = ((ViewStub) findViewById(R.id.stubView)).inflate();
Inflate()或可理解爲“隱性膨脹”,隱性擺放在view裏,inflate()前只是獲得控件,但沒有大小沒有在View裏佔據空間,inflate()後有一定大小,只是出於隱藏狀態
關於LayoutInflater對象的獲取,參考博文:
http://blog.csdn.net/ruancoder/article/details/51760942
今天主要對inflate()方法的使用和源碼進行分析。
(1).inflate()方法的使用
在實際使用中,我們一般會用到inflate的以下兩個重載方法。
方法一:
- public View inflate(int resource, ViewGroup root) {}
public View inflate(int resource, ViewGroup root) {}
方法二:
- public View inflate(int resource, ViewGroup root, boolean attachToRoot) {}
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {}
其中方法一最爲常見。
常見使用案例一:
- View myView = LayoutInflater.from(context).inflate(R.layout.my_view, null);
View myView = LayoutInflater.from(context).inflate(R.layout.my_view, null);
將佈局文件/res/layout/my_view.xml實例化爲myView對象。常見使用案例二:
- ViewGroup viewRoot;
- LayoutInflater.from(context).inflate(R.layout.my_view, viewRoot);
ViewGroup viewRoot;
LayoutInflater.from(context).inflate(R.layout.my_view, viewRoot);
將佈局文件/res/layout/my_view.xml實例化的View對象添加到viewRoot佈局中。那麼方法一與方法二有什麼區別呢?
進入方法一的源碼,我們會發現內部調用的其實就是方法二,只是將方法二的第3個參數設爲“root != null”。
- public View inflate(int resource, ViewGroup root) {
- return inflate(resource, root, root != null);
- }
public View inflate(int resource, ViewGroup root) {
return inflate(resource, root, root != null);
}
方法二中的參數和返回值釋義:
參數:
resource:需要實例化的佈局資源id。
root:ViewGroup類型視圖組對象
attachToRoot:是否將resource實例化後的View添加到參數root中。
返回值:
如果root爲空,直接返回resource實例化後的View對象;
如果root不爲空,attachToRoot爲true,將resource實例化爲view對象,忽略view的最外層視圖在xml佈局中定義的屬性,將view添加到root中,並將root返回。
如果root不爲空,attachToRoot爲false,將resource實例化爲view對象,爲view的最外層視圖設置其在xml佈局中定義的屬性,並將view對象返回。
(2).inflate()方法的源碼分析
進入inflate()方法內部。
- public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
- final Resources res = getContext().getResources();
- // 根據layout resource id,獲取該佈局的XmlResourceParser對象
- final XmlResourceParser parser = res.getLayout(resource);
- try {
- return inflate(parser, root, attachToRoot);
- } finally {
- parser.close();
- }
- }
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
// 根據layout resource id,獲取該佈局的XmlResourceParser對象
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
從方法內部可以看到,LayoutInflater使用的是pull解析器來解析xml佈局文件的。獲取到佈局resource的XmlResourceParser對象後,接着進入下一個方法。- public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
- // ...
- // attrs是傳入的佈局layout在xml文件裏面設置的屬性集合
- final AttributeSet attrs = Xml.asAttributeSet(parser);
- // 將ViewGroup類型的參數root賦值給result
- View result = root;
- // temp是傳入的參數resource的根佈局View
- final View temp = createViewFromTag(root, name, inflaterContext, attrs);
- ViewGroup.LayoutParams params = null;
- // 實例化temp視圖內的所有子視圖
- rInflateChildren(parser, temp, attrs, true);
- if (root != null) {
- // 根據attrs屬性集,創建佈局參數params
- params = root.generateLayoutParams(attrs);
- // 如果temp不需要添加到root中,那麼爲temp設置佈局參數params
- if (!attachToRoot) {
- temp.setLayoutParams(params);
- }
- }
- if (root != null && attachToRoot) {
- // 將temp添加到root中,並使用佈局參數params
- root.addView(temp, params);
- }
- if (root == null || !attachToRoot) {
- // 將temp賦值給result(在此之前,result==root)
- result = temp;
- }
- // ...
- return result;
- }
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
// ...
// attrs是傳入的佈局layout在xml文件裏面設置的屬性集合
final AttributeSet attrs = Xml.asAttributeSet(parser);
// 將ViewGroup類型的參數root賦值給result
View result = root;
// temp是傳入的參數resource的根佈局View
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
// 實例化temp視圖內的所有子視圖
rInflateChildren(parser, temp, attrs, true);
if (root != null) {
// 根據attrs屬性集,創建佈局參數params
params = root.generateLayoutParams(attrs);
// 如果temp不需要添加到root中,那麼爲temp設置佈局參數params
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
if (root != null && attachToRoot) {
// 將temp添加到root中,並使用佈局參數params
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
// 將temp賦值給result(在此之前,result==root)
result = temp;
}
// ...
return result;
}
該方法是inflate()的關鍵,這裏只抽取了需要關注的核心代碼。最開始,定義方法的返回值result,將參數root賦值給result,實例化參數resource賦值給temp。
接下來進入判斷條件。
當root!=null時,根據resource的最外層view在xml中定義的的屬性,創建佈局參數params。如果!attachToRoot,爲temp設置佈局參數params。
當root!=null&&attachToRoot,將temp添加到root中,並使用上面創建的佈局參數params。
當root==null||!attachToRoot,將temp賦值給result。
最後,將result返回。
邏輯看起來較繁瑣,簡單點可以這麼理解。
只要root==null,無視attachToRoot的值,創建temp對象,返回temp。
當root!=null時,分兩種情況。一,attachToRoot==true,將temp添加到root中,並使用佈局參數params,返回root。二,attachToRoot==false,爲temp設置佈局參數params,返回temp。
(3).inflate()方法代碼示例
在上面對inflate(int resource, ViewGroup root, boolean attachToRoot)方法的源碼分析中,關於參數和返回值及其中的邏輯不難理解,主要是方法內是否爲temp設置佈局參數有些難以理解。下面使用代碼示例進行說明。
創建MainActivity,並設置界面佈局activity_main.xml。
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"/>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
新建一個textview.xml。這裏故意給TextView的layout_width和layout_height設定了固定數值,並添加layout_gravity屬性。方便後面看出差異。
- <?xml version="1.0" encoding="utf-8"?>
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="230dp"
- android:layout_height="80dp"
- android:layout_gravity="center_horizontal"
- android:background="#999999"
- android:text="blog.csdn.net/ruancoder"
- android:textColor="#ffffff"
- android:textSize="18sp"/>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="230dp"
android:layout_height="80dp"
android:layout_gravity="center_horizontal"
android:background="#999999"
android:text="blog.csdn.net/ruancoder"
android:textColor="#ffffff"
android:textSize="18sp"/>
在MainActivity的onCreate()方法中,添加如下代碼。
- <pre name="code" class="java">package net.csdn.blog.ruancoder;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- public class MainActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- ViewGroup root = (ViewGroup) findViewById(R.id.layout);
- View textView = LayoutInflater.from(this).inflate(R.layout.textview, null);
- root.addView(textView);
- }
- }
<pre name="code" class="java">package net.csdn.blog.ruancoder;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewGroup root = (ViewGroup) findViewById(R.id.layout);
View textView = LayoutInflater.from(this).inflate(R.layout.textview, null);
root.addView(textView);
}
}
運行效果圖一:然後,將onCreate()方法中的代碼修改爲如下:
- ViewGroup root = (ViewGroup) findViewById(R.id.layout);
- LayoutInflater.from(this).inflate(R.layout.textview, root, true);
ViewGroup root = (ViewGroup) findViewById(R.id.layout);
LayoutInflater.from(this).inflate(R.layout.textview, root, true);
或- ViewGroup root = (ViewGroup) findViewById(R.id.layout);
- View textView = LayoutInflater.from(this).inflate(R.layout.textview, root, false);
- root.addView(textView);
ViewGroup root = (ViewGroup) findViewById(R.id.layout);
View textView = LayoutInflater.from(this).inflate(R.layout.textview, root, false);
root.addView(textView);
兩種方式中的任意一種。然後再看運行效果。
運行效果圖二:
從圖一的顯示效果可以看出,我們爲TextView設定的layout屬性都失去了作用。而在圖二中,這三個layout屬性都正常顯示出來了。