簡體   English   中英

如何將兩個片段與 Android 導航組件鏈接?

[英]How can I link two fragments with Android Navigation component?

我正在使用帶有底部導航欄的 Android Jetpack 的導航組件,如下所示:

Navigation graph: "mobile_navigation.xml"

Bottom navigation bar: "BottomNavigationView"

讓我們關注 Home 和 Dashboard 目的地,Dashboard 顯示部門列表,每個部門顯示產品列表,每個產品顯示詳細描述。 到目前為止一切正常。

但是Home 應該直接顯示完整的產品列表,這里有一個問題:如何在應用程序啟動時(以及每次訪問 Home 時)直接在 Home 上顯示product_list片段?

請注意,我不能將product_list代碼直接放入 Home 片段,因為從儀表板導航將 go 到 Home。

另外,如果我將findNavController().navigate(HomeFragmentDirections.nextAction())放在主頁片段onCreateView(...)上,每次我 go 到主頁時,它都會顯示產品列表,而且還會顯示應用欄上的向上按鈕,它不會去任何地方(它會轉到再次重定向到product_list的 Home)。

App action bar: "Toolbar"

通過儀表板上的部門列表訪問product_list時,我只需要向上按鈕。 product_list應該顯示在 Home 上,就好像它是 Home 本身一樣。

因此,我正在尋找一種方法來直接鏈接這兩個片段,無需任何事務,或者避免應用程序欄上的向上按鈕(可能通過避免將事務添加到事務返回堆棧)。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bottom_nav"
    app:startDestination="@+id/navigation_home">

    <fragment
        android:id="@+id/navigation_home"
        android:name="cu.lcnicolau.ui.home.HomeFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_home">
        <action
            android:id="@+id/next_action"
            app:destination="@id/product_list">
            <argument
                android:name="departmentId"
                android:defaultValue="0" />
        </action>
    </fragment>

    <fragment
        android:id="@+id/navigation_departments"
        android:name="cu.lcnicolau.ui.departments.DepartmentsFragment"
        android:label="@string/title_departments"
        tools:layout="@layout/fragment_departments">
        <action
            android:id="@+id/next_action"
            app:destination="@id/product_list" />
    </fragment>

    <fragment
        android:id="@+id/product_list"
        android:name="cu.lcnicolau.ui.products.ItemListFragment"
        android:label="@string/title_products"
        tools:layout="@layout/item_list">
        <action
            android:id="@+id/next_action"
            app:destination="@id/product_detail" />
        <argument
            android:name="departmentId"
            app:argType="integer" />
    </fragment>

    <fragment
        android:id="@+id/product_detail"
        android:name="cu.lcnicolau.ui.products.ItemDetailFragment"
        android:label="@string/title_product_detail"
        tools:layout="@layout/item_detail">
        <argument
            android:name="item"
            app:argType="cu.lcnicolau.dummy.Product" />
    </fragment>

</navigation>

這種方式可能會滿足您的需求:

1.設置bottom_nav

  1. 創建可在導航圖中的任何位置使用的全局操作。 DepartmentsFragment將使用它導航到ItemListFragment

  2. navigation_home中創建操作。 這里的重要屬性是app:popUpTo="@+id/bottom_nav (你的圖 id),當從其他 Fragment 調用 onBackPressed 時,它將從 backstack 中刪除 HomeFragment 並影響到 BottomNavigationView。我們將使用 ActivityCallback 來解決這個問題。

 <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/bottom_nav" app:startDestination="@+id/navigation_home"> <action android:id="@+id/to_product_list" app:destination="@id/product_list" /> <fragment android:id="@+id/navigation_home" android:name="com.example.stackoverflowhelps.ui.home.HomeFragment" android:label="@string/title_home" tools:layout="@layout/fragment_home"> <action android:id="@+id/home_to_product_list" app:destination="@id/product_list" app:popUpTo="@+id/bottom_nav" /> </fragment> <fragment android:id="@+id/product_list" android:name="com.example.stackoverflowhelps.ui.products.ProductsFragment" android:label="@string/title_products" tools:layout="@layout/fragment_products" > <argument android:name="departmentId" app:argType="long" /> </fragment>... </navigation>

  1. DepartmentsFragment調用全局操作

 findNavController().navigate(toProductList(departementId))

  1. HomeFragment初始回調中的任何位置

 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) findNavController().navigate(homeToProductList(-1)) }


2.設置MainActivity和NavCallback

此回調的目的是在從其他兩個底部菜單 onBackPressed 時將 BottomNavigationView 導航到 Home。 由於我們在后台堆棧中丟失了 HomeFragment,因此我們每次從 Home 輸入 ItemListFragment。

  1. NavCallback.java

     interface NavCallback { enum class Nav { HOME, DASHBOARD, OFFERS } fun navigateToMenu(nav: Nav) }

  2. MainActivity.java

     class MainActivity: AppCompatActivity(), NavCallback { private lateinit var navView: BottomNavigationView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) navView = findViewById(R.id.nav_view) val navController = findNavController(R.id.nav_host_fragment) // optional: if you want to permanently remove default ActionBar BackButton from ItemListFragment, add product_list navigation id to appBarConfiguration val appBarConfiguration = AppBarConfiguration( setOf( R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_offers, R.id.product_list ) ) setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) } override fun navigateToMenu(nav: NavCallback.Nav) { val dest: Int = when(nav) { NavCallback.Nav.HOME -> R.id.navigation_home NavCallback.Nav.DASHBOARD -> R.id.navigation_home NavCallback.Nav.OFFERS -> R.id.navigation_notifications } navView.selectedItemId = dest } }

  3. DepartmentsFragmentOffersFragment NavCallback 我們將手動將 select 底部導航菜單轉到 Home,請參閱NavCallback.Nav.HOME

 class DepartmentsFragment: Fragment() { private var navCallback: NavCallback? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val callback = object: OnBackPressedCallback(true) { override fun handleOnBackPressed() { navCallback?.navigateToMenu(NavCallback.Nav.HOME) } } requireActivity().onBackPressedDispatcher.addCallback(this, callback) } override fun onAttach(context: Context) { super.onAttach(context) try { navCallback = context as NavCallback } catch (e: ClassCastException) { activity.toString() + " must implements NavCallback" } } override fun onDetach() { navCallback = null super.onDetach() }... }

到這里為止,我們已經得到了想要的 UI 流程。


3、確定ItemListFragment中的Product List數據和Back Button的可見性

出於方便的原因,我更喜歡使用自定義工具欄視圖和后退按鈕。 這時候我們將使用參數departmentId來確定返回按鈕的可見性

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val departmentId: Long = arguments?.getLong("departmentId")?: 0 if (departmentId > 0) { textView.text = departmentId.toString() back.visibility = View.VISIBLE back.setOnClickListener { requireActivity().onBackPressed() } // from fetch the data with given id } else { back.visibility = View.GONE // come from HomeFragment, fetch all data } }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM