如何用Android导航组件链接两个碎片?

问题描述 投票:0回答:1

我使用的是 Android Jetpack的导航组件 附带 底部导航栏,像这样。

Navigation graph: "mobile_navigation.xml"

  Bottom navigation bar: "BottomNavigationView"

让我们把注意力集中在主页和Dashboard上 Dashboard会显示一个部门列表 每个部门会显示一个产品列表 每个产品会显示一个详细的描述。到目前为止,一切都能正常工作。

然而。首页应直接显示全部产品列表,这里的问题是:我怎样才能显示出的 product_list 当应用程序启动时(以及每次访问Home时),直接将片段放在Home上?

注意,我不能把 product_list 代码直接放到Home片段中,因为这样的话,Dashboard的导航就会转到Home。

另外,如果我把 findNavController().navigate(HomeFragmentDirections.nextAction()) 关于 "家园 "部分 onCreateView(...)每次我进入 "主页 "时,它都会显示产品列表,但同时也会显示 "我的产品"。涨幅 按钮,但它没有去任何地方(它去了主页,而主页又重定向至 product_list 再次)。)

  App action bar: "Toolbar"

我只需要 涨幅 按钮时,访问 product_list 通过Dashboard上的部门列表。该 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>
android android-fragments kotlin bottomnavigationview android-architecture-navigation
1个回答
0
投票

这种方式或许能满足你的需求。

1. 设置 bottom_nav

  1. 创建可在导航图内任何地方使用的全局操作。DepartmentsFragment 将使用该操作导航到 ItemListFragment.

  2. 创建动作内 navigation_home. 这里的重要属性是 app:popUpTo="@+id/bottom_nav (你的图形id),当其他片段调用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。由于我们每次从Home进入ItemListFragment时,都会在backstack中丢失HomeFragment。

  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. 使用 NavCallback 内覆盖onBackPressed时 DepartmentsFragmentOffersFragment. 我们将手动选择底部导航菜单为 "首页",请看。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

为了方便起见,我更喜欢使用自定义工具栏视图和后退按钮。此时,我们将使用参数 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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.