繁体   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