如果你通讀了本系列的前兩篇,我相信你可以寫出大部分場景都能正常執行的Fragment了。如果你想了解更多,那麼你可以看看我封裝的這個庫:Fragmentation。
本篇主要介紹這個庫,解決了一些BUG,使用簡單,提供實時檢視棧檢視等實用功能。
原始碼地址:Github,歡迎Fork,提Issues 。
Demo網盤下載
Demo演示:單Activity+多Fragment
Fragmentation
為”單Activity + 多Fragment的架構”,”多模組Activity + 多Fragment的架構”而生,幫你簡化使用過程,修復了官方Fragment庫存在的一些BUG。
特性
1、為重度使用Fragment而生
2、提供了方便的管理Fragment的方法
3、有效解決Fragment重疊問題
4、實時檢視Fragment的(包括巢狀Fragment)棧檢視,方便Fragment巢狀時的除錯
5、增加啟動模式、startForResult等類似Activity方法
6、修復官方庫裡pop(tag/id)出棧多個Fragment時的一些BUG
7、完美解決進出棧動畫的一些BUG,更自由的管理Fragment的動畫
8、支援SwipeBack滑動邊緣退出(需要使用Fragmentation_SwipeBack庫,詳情README)
如何使用
1、專案下app的build.gradle中依賴:
1 2 |
compile 'me.yokeyword:fragmentation:0.5.2' // appcompat v7包也是必須的 |
2、Activity繼承SupportActivity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class MainActivity extends SupportActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(...); if (savedInstanceState == null) { start(HomeFragment.newInstance()); } } /** * 設定Container的id,必須實現 */ @Override public int setContainerId() { return R.id.fl_container; } /** * 設定全域性動畫,在SupportFragment可以自由更改其動畫 */ @Override protected FragmentAnimator onCreateFragmentAnimator() { // 預設豎向(和安卓5.0以上的動畫相同) return super.onCreateFragmentAnimator(); // 設定橫向(和安卓4.x動畫相同) // return new DefaultHorizontalAnimator(); // 設定自定義動畫 // return new FragmentAnimator(enter,exit,popEnter,popExit); } |
3、Fragment繼承SupportFragment
API
SupportActivity
開啟 棧檢視 的提示框,在複雜巢狀的時候,可以通過這個來清洗的理清不同階級的棧檢視。
1 2 |
// 彈出 棧檢視 提示框 showFragmentStackHierarchyView(); |
除此之外包含大部分SupportFragment的方法,請自行檢視。
SupportFragment
1、啟動相關:
1 2 3 4 5 6 7 8 |
// 啟動新的Fragment start(SupportFragment fragment) // 以某種啟動模式,啟動新的Fragment start(SupportFragment fragment, int launchMode) // 啟動新的Fragment,並能接收到新Fragment的資料返回 startForResult(SupportFragment fragment,int requestCode) // 啟動目標Fragment,並關閉當前Fragment startWithFinish(SupportFragment fragment) |
2、關閉Fragment:
1 2 3 4 5 6 7 8 9 |
// 關閉當前Fragment pop(); // 關閉某一個Fragment棧內之上的Fragments popTo(Class fragmentClass, boolean includeSelf); // 如果想出棧後,緊接著開始.beginTransaction()開始一個事務,請使用下面的方法: // 在 第二篇 文章內的 Fragment事務部分的問題 有解釋原因 popTo(Class fragmentClass, boolean includeSelf, Runnable afterTransaction) |
3、在SupportFragment內,支援監聽返回按鈕事件:
1 2 3 4 5 |
@Override public boolean onBackPressedSupport() { // 返回false,則繼續傳遞返回事件; 返回true則不繼續傳遞 return false; } |
4、 定義當前Fragment的動畫,複寫onCreateFragmentAnimation
方法:
1 2 3 4 5 6 7 8 9 10 11 |
@Override protected FragmentAnimator onCreateFragmentAnimation() { // 獲取在SupportActivity裡設定的全域性動畫物件 FragmentAnimator fragmentAnimator = _mActivity.getFragmentAnimator(); fragmentAnimator.setEnter(0); fragmentAnimator.setExit(0); return fragmentAnimator; // 也可以直接通過 // return new FragmentAnimator(enter,exit,popEnter,popExit)設定一個全新的動畫 } |
5、獲取當前Activity/Fragment內棧頂(子)Fragment:
1 |
getTopFragment(); |
6、獲取棧內某個Fragment物件:
1 2 3 4 |
findFragment(Class fragmentClass); // 獲取某個子Fragment物件 findChildFragment(Class fragmentClass); |
更多
隱藏/顯示 輸入法:
1 2 3 4 |
// 隱藏軟鍵盤 一般用在onHiden裡 hideSoftInput(); // 顯示軟鍵盤 showSoftInput(View view); |
下面是DetailFragment startForResult
ModifyTitleFragment的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
DetailFragment.class裡: startForResult(ModifyDetailFragment.newInstance(mTitle), REQ_CODE); @Override public void onFragmentResult(int requestCode, int resultCode, Bundle data) { super.onFragmentResult(requestCode, resultCode, data); if (requestCode == REQ_CODE & resultCode == RESULT_OK ) { // 在此通過Bundle data 獲取返回的資料 } } ModifyTitleFragment.class裡: Bundle bundle = new Bundle(); bundle.putString("title", "xxxx"); setFramgentResult(RESULT_OK, bundle); |
下面是以一個singleTask模式start
一個Fragment的標準程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
HomeFragment fragment = findFragment(HomeFragment.class); if (fragment == null) { fragment = HomeFragment.newInstance(); }else{ Bundle newBundle = new Bundle(); // 傳遞的bundle資料,會呼叫目標Fragment的onNewBundle(Bundle newBundle)方法 fragment.putNewBundle(newBundle); } // homeFragment以SingleTask方式啟動 start(fragment, SupportFragment.SINGLETASK); // 在HomeFragment.class中: @Override protected void onNewBundle(Bundle newBundle){ // 在此可以接收到資料 } |
關於Fragmentation幫你恢復Fragment,你需要知道的
2個概念:
“同級”式:比如QQ的主介面,“訊息”、“聯絡人”、“動態”,這3個Fragment屬於同級關係
“流程”式:比如登入->註冊/忘記密碼->填寫資訊->跳轉到主頁Activity
對於Activity內的“流程”式Fragments(比如登入->註冊/忘記密碼->填寫資訊->跳轉到主頁Activity),Fragmentation幫助你處理了棧內的恢復,保證Fragment不會重疊,你不需要再自己處理了。
但是如果你的Activity內的Fragments是“同級”的,那麼需要你複寫onHandleSaveInstanceState()
使用findFragmentByTag(tag)
或getFragments()
去恢復處理。
1 2 3 4 5 6 |
@Override protected void onHandleSaveInstancState(Bundle savedInstanceState) { // 複寫的時候 下面的super一定要刪掉 // super.onHandleSaveInstancState(savedInstanceState); // 在此處 通過findFragmentByTag或getFraments來恢復,詳情參考第二篇文章 } |
而如果你有Fragment巢狀,那麼不管是“同級”式還是“流程”式,你都需要自己去恢復處理。