定義:A Fragment represents a behavior or a portion of user interface in an Activity.
一個Activity可包括多個Fragments,用來創建一個多pane的UI,並可在多個Activity中重用這些Fragment。此外,可將其看做是一個Activity的模塊化部分,它有本身的生命週期,可接受用戶輸入,可在Activity運行時進行添加或者修改。
一個Fragment必須嵌入到一個Activity中,且受宿主Activity的影響。如Activity pause了,那麼全部的Fragment都將進入pause,當全部Activity destory了,全部的Fragment也都destory了。當Activity在運行時,可添加或者刪除fragment,還能夠將其加入back stack,這樣可經過back button 進行回退。
當添加一個Fragment時,它將做爲ViewGroup的一個部分,而且可定義本身的View。可經過在Activity的代碼中插入< fragment>標籤,或者在運行時將其添加到一個已經存在ViewGroup。
然而Fragment並不一必定要做爲Activity Layout的一部分,它也能夠是無UI的,做爲Activity不可見的Worker。android
- OnCreate(), 初始化必須的組建,即須要在fragement的onPause, onStop, onResume等狀態時retain這些。
- onCreateView(), 爲Fragemnt建立UI,而且須要返回佈局的根View。若是該fragment不須要界面,也能夠返回Null。
- onPause(), 這是指示用戶須要離開該fragment,所以須要提交須要持久化的數據。app
還有3個Fragment能夠繼承的:less
提供用戶接口,必須實現onCreateView(),返回佈局的根View。如果ListFragment,則返回ListView。
To return a layout from onCreateView(), 可inflate an xml layout resource。 onCreateView的默認參數包含了一個LayoutInflater的對象。
代碼以下:ide
public static class ExampleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.example_fragment, container, false); } }
其中 container 是Activity佈局裏的ViewGroup對象,而後inflate出來的佈局會被出入到該container。Bundler則是用於傳遞參數或者其餘恢復佈局的狀態。然而,inflate方法的3個參數,第一個爲佈局的resource id, 第二個爲container, 第3個指示是否須要attach 到 viewgroup,因爲指定了container,於是此處應設爲false,不然Android System將會create a redundant view group in the final layout.模塊化
two ways to add。
1. 在activity的xml layout文件中,聲明fragment xml 佈局文件。佈局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:name="com.example.news.ArticleListFragment" android:id="@+id/list" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.news.ArticleReaderFragment" android:id="@+id/viewer" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>
其中android:name 屬性爲指定Fragment類來初始化layout。在系統初始話該佈局時,它會初始化每一個fragment類,而後調用onCreateView()方法,獲取到每一個fragment的佈局。
爲了重用the fragment,須要爲每一個fragment分配一個unique id:使用android:id; 使用adndroid:tag; 不設置,系統使用container的id。
2. 代碼中添加到一個現存的ViewGroup動畫
// 獲取fragmentTransaction,就可實現諸如add, remove, or replace a fragment等行爲。 FragmentManager fragmentManager = getFragmentManager() FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); // 添加一個fragment到R.id.fragment_container,並提交。 ExampleFragment fragment = new ExampleFragment(); fragmentTransaction.add(R.id.fragment_container, fragment); fragmentTransaction.commit();
可將該fragment做爲一個後臺worker。
方法:ui
使用add(Fragment, String), 其中String是一個字符串tag,因爲不提供layout給activity,所以該fragment也無需建立onCreateView()。tag將做爲該fragment的標識,並使用findFragmentByTag()方法來尋找。this
- getFragmentById(), or getFragmentByTag();
- pop fragments off the back stack with popBackStack()
- addOnBackStackChangedListener(), register a listener for changes。
- open a FragmentTransaction, 處理add, remove fragment等事務。spa
Steps:
1. acquire an instance of FragmentTransaction
FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Create new fragment and transaction Fragment newFragment = new ExampleFragment(); FragmentTransaction transaction = getFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit();
上述代碼替換掉container中的當前fragment。
若調用了多個操做,add,replace等且調用了addToBackStack,在commit以前的全部操做都會被保存,並可被一塊兒恢復。
commit必須被最後執行,添加多個fragment到同一個container,添加順序將絕定每一個fragment在view hierarchy的順序。
Tip:, 調用setTransition(),可爲fragment之間的切換添加動畫。另,若不調用addToBackStack,則調用remove,該fragment就會被destory。如果調用了addToBackStack,則該fragment將進入stopped,而且可被resumed when the user navigate it。
此外,commit()不是馬上執行transation,而是會根據主線程調度狀況執行。除非必需要馬上執行,可調用executePendingTransaction()。
最後須要注意的是,commit()必須先於activity的saving its state(即pause或stop),不然將致使異常。解決這個問題,可調用cimmitAllowingStateless()。
View listView = getActivity.findViewById(R.id.list)
ExampleFragment fragment = getFragmentManager.findFragmentById(R.id.example_fragment);
public static class FragmentA extends ListFragment { ... // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onArticleSelected(Uri articleUri); } ... }
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); } } ... }
mListener.onArticleSelected(uri)
事件處理流程是Activity先處理,發現無人處理後纔會向下傳遞到fragment中。
管理一個生命週期,仍然包括三個態:
- Resumed,運行時,可見。
- Paused, 被另外一個Activity擋住了,但本Activity仍然可見(未被徹底遮住,如dialog)。
- Stopped, 徹底不可見,但all state and member information is retained by the system。
可用onSaveInstanceState()保存數據,並在onCreate(), onCreateView(), or onActivityCreated()中重裝。
其中Activity會自動進入BackStack,而fragment須要明確調用addToBackStack()。