一個輪子搞定 Fragment 和狀態列那些事

非非白發表於2018-04-08

今天給大家介紹一個開源庫,看完後,很多 fragment 以及狀態列相關的煩惱將離你而去。

我不喜歡囉嗦,讓我們直入主題吧。

搞定 fragment 那些事

fragment 有哪些煩惱?

動畫不正常,尤其是有 fragment 巢狀的時候?

can not perform this action after onSaveInstanceState 異常?

不正常的重影?

煩人的生命週期?

不知道用哪個 fragmentManager?

AndroidNavigation 來拯救世界

下載體驗 apk

建議分別在 Android 4.4、5.0 和 6.0 下體驗

一行程式碼實現 Fragment 巢狀,一次性構建好巢狀層級

AndroidNaviation 提供了幾款常用的容器來幫助我們快速實現 fragment 巢狀,分別是 DrawerFragment, TabBarFragment, NavigationFragment

看名字不難理解,DrawerFragment 為我們提供了抽屜的能力,是一個很拉風的抽屜哦,當開啟時,狀態列會自動隱藏。

一個輪子搞定 Fragment 和狀態列那些事

相信我,你們的設計師會喜歡的。

TabBarFragment 為我們提供了 BottomNavigationBar 選項卡的能力,譬如微信、支付寶主頁面底部都會有一個

一個輪子搞定 Fragment 和狀態列那些事

NavigationFragment 則以棧的形式管理它的子 fragment, 並且提供了轉場動畫。巢狀在 NavigationFragment 裡面的子 fragment 會受到祝福,擁有自動建立 Toolbar 的能力,並在恰當的時機自動新增返回按鈕。

一個輪子搞定 Fragment 和狀態列那些事

如果一個應用的主頁面,既有 drawer 也有 tabs,每個 tab 的頁面還要能切換到其它頁面,看起來很複雜的巢狀吧。但 AndroidNavigation 可以一次性就把這些 UI 層級構建好

// MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        // 首頁
        HomeFragment homeFragment = new HomeFragment();
        NavigationFragment homeNavigatoinFragment = new NavigationFragment();
        homeNavigationFraggment.setRootFragment(homeFragment);
        homeNavigatoinFragment.setTabBarItem(new TabBarItem(R.drawable.icon_home, "首頁"));
        
        // 通訊錄
        ContactsFragment contactsFragment = new ContactsFragment();
        NavigationFragment contactsNavigationFragment = new NavigationFragment();
        contactsNavigationFragment.setRootFragment(contactsFragment);
        contactsNavigationFragment.setTabBarItem(new TabBarItem(R.drawable.icon_contacts, "通訊錄"));
        
        // 新增 tab 到 TabBarFragment 
        TabBarFragment tabBarFragment = new TabBarFragment();
        tabBarFragment.setFragments(homeNavigatoinFragment, contactsNavigationFragment);
        
        // drawer
        DrawerFragment drawerFragemnt = new DrawerFragment();
        MenuFragment menuFragment = new MenuFragment();
        drawerFragment.setMenuFragment(menuFragment);
        drawerFragment.setContentFragment(tabBarFragment);
        drawerFragment.setMaxDrawerWidth(300); // 設定 menu 的最大寬度
        
        // 把 DrawerFragment 設定為 Activity 的根
        setRootFragment(drawerFragemnt);
    }
}
複製程式碼

就這樣,我們把上面提到的 UI 層級構建好了,一共有四層 fragment 巢狀哦,恐怖不恐怖,興奮不興奮?

這些容器還不能滿足你的需求?自定義容器!

我們的 ViewPagerFragment 就是個自定義容器

一個輪子搞定 Fragment 和狀態列那些事

核心程式碼

// ViewPagerFragemnt.java

int location;

@Override
public boolean isParentFragment() {
    return true;
}

@Override
protected int preferredStatusBarColor() {
    int[] colors = new int[] {Color.RED, Color.GREEN, Color.BLUE};
    return colors[location];
}

private void initView(View view) {
    AppBarLayout appBarLayout = view.findViewById(R.id.appbar_layout);
    // important
    if(isStatusBarTranslucent()) {
        appendStatusBarPadding(appBarLayout, -2);
    }
}
複製程式碼

並不複雜

一行程式碼實現 Fragment 跳轉,不再需要寫一大堆操作 fragment 的程式碼了,不用擔心用錯 FragmentManager 了

所有的 fragment 都具備兩個基本的導航能力 presentFragment 以及 dismissFragment,就是開啟和關閉一個 fragment

// HomeFragment.java
presentFragment(new TargetFragment(), REQUEST_CODE);
複製程式碼

一行程式碼就跳過去了

帶上個請求碼,TargetFragment 在關閉前可以通過 setResult 返回結果給前一個頁面

 Bundle result = new Bundle();
 result.putString("text", resultEditText.getText().toString());
 setResult(Activity.RESULT_OK, result);
 dismissFragment();//關閉
複製程式碼

如果 fragemnt 巢狀在 NavigationFragment 中,會有更多的導航能力, 比如

  • push 入棧一個介面
  • pop 出棧一個介面
  • popTo 同時出棧多個介面到指定介面,而且不用擔心一次出棧多個介面,動畫會有問題

對上面這些導航不滿意?自定義導航!

一個輪子搞定 Fragment 和狀態列那些事

具體實現參考 demo 中 GridFragment 這個類

懶載入

AndroidNavigation 提供了兩個生命週期函式來幫助我們實現懶載入

protected void onViewAppear();
protected void onViewDisappear();
複製程式碼

搞定狀態列那些事

狀態列的煩事有哪些?

沉浸式以及沉浸式帶來的 BUG ?

白底黑字但結果 5.0 以下全是白的?

想要將沉浸式以及狀態列顏色相容到 4.4?

啥,鍵盤不頂用了?

一行程式碼開關沉浸式狀態列,相容到 Android 4.4 並解決了相關 BUG

// 開啟沉浸式
setStatusBarTranslucent(true);
複製程式碼

一個輪子搞定 Fragment 和狀態列那些事

其它諸如狀態列顏色,只需要有選擇性地重寫以下方法,返回期待的結果即可

// 狀態列字型風格,黑或白
protected BarStyle preferredStatusBarStyle();
// 是否隱藏狀態列
protected boolean preferredStatusBarHidden();
// 狀態列顏色
protected int preferredStatusBarColor();
// 切換狀態列顏色時,是否平滑過渡
protected boolean preferredStatusBarColorAnimated();
複製程式碼

就是這麼簡單

關於 AndroidNavigation 更多功能更詳細的描述,請看這裡 README

喜歡的話記得給顆星星,因為要集齊 100 顆才可以召喚神龍。

相關文章