Fragment
1,簡介
Fragment名為碎片和Activity相似。
Fragment用來描述一些行為或一部分用戶界面在一個Activity中,你可以合並多個fragment在一個單獨的activity中建立多個UI面板,同時重用fragment在多個activity中.你可以認為fragment作為一個activity中的一節模塊 ,fragment有自己的生命周期,接收自己的輸入事件,你可以添加或移除從運行中的activity.
Fragment作為Android 3.0的新特性,有些功能還是比較強大的,比如 合並兩個Activity:
可以看到兩個Activity通過兩個Fragment合並到一個Activity的布局方式,對於平板等大屏幕設備來說有着不錯的展示面板。
如下例子,在一個activity的布局文件中嵌入兩個fragment:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />
<fragment android:name="com.aaa.MainActivity$MyFragment" android:id="@+id/fg1" android:layout_width="match_parent" android:layout_height="wrap_content" />
<fragment android:name="com.aaa.MainActivity$MyFragment2" android:id="@+id/fg2" android:layout_width="match_parent" android:layout_height="wrap_content" />
</LinearLayout> |
這樣就把兩個fragment嵌入到了使用該布局文件的activity中。 使用很簡單,和普通的Veiw沒有區別。這樣也就有一個好處是,布局文件可以重復使用(類似include)。需要說明的是嵌入的Fragment存在於Activity的ViewGroup中。
Settings模塊使用PreferenceActivity
Settings模塊主界面就是繼承自PreferenceActivity,采用headers和fragment來顯示。
public class Settings extends PreferenceActivity … { …. @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.settings_headers, target); …. } …. } |
顯示界面使用PreferenceFragment
顯示界面都是直接或簡介繼承自Fragment。比如:網絡設置WirelessSettings繼承自PreferenceFragment,PreferenceFragment是Fragment子類,我們可以根據不同需求來選擇使用哪個Fragment,就像選擇Activity和ListActivity一樣。
①Fragment:你可以在onCreate方法中使用res/layout/xxx.xml文件,就像activity一樣。
②PreferenceFragment:如果你顯示的為列表,那么你就可以使用PreferenceFragment來實現,它里封裝了ListView用作列表顯示。其使用的布局文件為res/xml/xxx.xml
由上可知道Settings界面布局和架構。
例子:
使用fragment和view進行布局。
效果圖:
采用相對布局,左邊是一個Fragment,右邊是兩個上下顯示的fragment。
JAVA代碼如下:定義了三個 fragment,分別使用各自的布局文件。
public static class MyFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.myfragment, container, false); } } public static class MyFragment2 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.myfragment2, container, false); } }
public static class MyFragment3 extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.my_fragmented2); } } |
2,生命周期
一個fragment必須總是嵌入在一個activity中,同時fragment的生命周期受activity而影響。
其生命周期如下圖所示:
可看見Framment生命周期比較復雜,如果你熟悉activity的生命周期,那么Fragment的生命周期也是類似的。Activity和fragment回調順序如下:
activity.onCreate
fragment.onAttach
fragment.onCreate
activity.onStart
fragment.onActivityCreated
fragment.onStart
activity.onResume
fragment.onResume
fragment.onStop
activity.onStop
fragment.onDestroyView
fragment.onDestroy
fragment.onDetach
activity.onDestroy
可知道當activity 暫停,那么所有在這個activity的fragments將被destroy釋放。 你可以在activity的不同生命周期中,對fragment執行不同操作。
3,Fragment簡單示例
自定義一個fragment,需要繼承(或間接繼承)Fragment類。
public class MyFragment extends Fragment {
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.myfragment, container, false); }
} |
onCreateView()
當系統調用fragment在首次繪制用戶界面時,如果畫一個UI在你的fragment你必須返回一個View當然了你可以返回null代表這個fragment沒有UI.
myfragment.xml. 和普通的layout定義完全一樣。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/btn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> |
FragmentManager
可以使用FragmentManager來管理Fragment。在Activity中通過getFragmentManager來獲得。FragmentManager 類一些主要的方法有通過findFragmentById()來獲取一個Activity中有關Fragment布局。當然還有類似findFragmentByTag()方法,以及當Fragment中出棧的popBackStack()同時可以注冊 addOnBackStackChangedListener()管理。具體的可以在android.app.FragmentManager類中了解。
可以使用FragmentManager進行事物處理。
//通過begintransaction方法獲取一個事物處理實例。
FragmentTransaction transaction = fragmentManager.beginTransaction();
在這期間可以使用 add(), remove()和replace()。最終需要改變時執行 commit()即可。
如下例子:替換activity的布局為,MyFragment。
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, "onCreate");
FragmentManager fragmentManager = this.getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(android.R.id.content, new MyFragment()); fragmentTransaction.commit(); } |
我們可以使用FragmentManager來獲取嵌入到activity的fragment。
<fragment android:name="com.aaa.MainActivity$MyFragment" android:id="@+id/myFg" android:tag="myFragment" android:layout_width="match_parent" android:layout_height="wrap_content" /> |
getFragmentManager().findFragmentById(R.id.myFg);
getFragmentManager().findFragmentByTag(“myFragment”);
Headers及其使用
Headers在平板上和Fragment結合使用的比較多。如Settings模塊。
我們使用就繼承自PreferenceActivity,然后重寫onBuildHeaders方法,調用loadHeadersFromResource方法加載headers.xml。
my_headers.xml
<?xml version="1.0" encoding="utf-8"?> <preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header android:fragment="com.aaa.MyHeadersPreferenceActivity$MyFragmentTest1" android:icon="@drawable/ic_1" android:title="Prefs Test 1" android:summary="An example of some preferences." />
<header android:fragment="com.aaa.MyHeadersPreferenceActivity$MyFragmentTest2" android:icon="@drawable/ic_2" android:title="Prefs Test 2" android:summary="Some other preferences you can see."> <!-- Arbitrary key/value pairs can be included with a header as arguments to its fragment. --> <extra android:name="someKey" android:value="someHeaderValue" /> </header>
<header android:icon="@drawable/ic_3" android:title="Test Intent" android:summary="Launches an Intent."> <intent android:action="android.intent.action.VIEW" android:data="http://www.baidu.com/" /> </header>
</preference-headers> |
可看見1,在header中能夠直接配置一個Fragment;2,能夠使用extra標簽來,傳遞參數;3,可直接配置一個Intent。 具體其它參數也不用多說了。
MyHeadersPreferenceActivity
public class MyHeadersPreferenceActivity extends PreferenceActivity {
@Override public void onBuildHeaders(List<Header> target) { Log.i(TAG, "onBuildHeaders"); loadHeadersFromResource(R.xml.my_headers, target); }
public static class MyFragmentTest1 extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// Load the preferences from an XML resource addPreferencesFromResource(R.xml.my_fragmented1); } }
public static class MyFragmentTest2 extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// Can retrieve arguments from headers XML. Log.i(this.getClass().getSimpleName(), "Arguments: " + getArguments());
// Load the preferences from an XML resource addPreferencesFromResource(R.xml.my_fragmented2); } } } |
類比較簡單,繼承自Preferencectivity,重寫onBuildHeaders方法,在此方法中加載headers。還有2個Fragment類前邊已經說過了,此處不表。
my_fragment1ed1.xml
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <CheckBoxPreference android:key="checkbox_preference_" android:title="Checkbox Test title" android:summary="Checkbox Test summary." /> </PreferenceScreen> |
很簡單,挺眼熟吧。
從例子中,可以看出,Headers使用也比較簡單。用它結合Fragment和Preference來進行界面布局和用戶交互操作很方便。
具體例子API Demo中有。