Navigation Architecture Component 3

9.使用menus, drawers 和 bottom navigation进行导航

NavigationUI and navigation-ui-ktx

导航组件包括一个NavigationUInavigation-ui-ktx Kotlin扩展。NavigationUI包含有将menu items和destination相关的静态方法,navigation-ui-ktx干一样的事情,是一堆扩展函数的集合。
如果NavigationUI发现某个menu item的ID和导航图中某个destination的ID相同,那么就配置为menu item将会导航到这个destination。

Using NavigationUI with an Options menu

使用NavigationUI最简单的方法是简化option menu设置,特别是简化onOptionsItemSelected callback。

1.打开MainActivity
注意这里在onCreateOptionsMenu中已经填充了overflow_menu
2.打开overflow_menu.xml
3.撸代码

    

4.打开MainActivity
5.让NavigationUI使用onNavDestinationSelected帮助处理onOptionsItemSelected,如果某个item不需要进行导航,那么用super.onOptionsItemSelected处理就可以。
6.跑起来,就有菜单了。

使用NavigationUI 配置 Bottom Navigation

代码中已经包含了底部导航布局,不过哪里都不能导航就是了。

1.打开res/layout/navigation_activity/navigation_activity.xml (h470dp),注意看代码,底部导航栏关联到了bottom_nav_menu.xml
2.打开bottom_nav_menu.xml
菜单中两个item的ID已经和导航图中两个destination匹配了。


    
    

我们让底部导航可以整出来一点事情。
3.打开MainActivity
4.实现setupBottomNavMenu

    private fun setupBottomNavMenu(navController: NavController) {
    // TODO STEP 9.3 - Use NavigationUI to set up Bottom Nav
    val bottomNav = findViewById(R.id.bottom_nav_view)
    bottomNav?.setupWithNavController(navController)
    // TODO END STEP 9.3
}
Using NavigationUI to configure a Navigation Drawer

现在我们来配置侧边导航和导航抽屉,包括处理ActionBar和proper up navigation。You'll see this if you've got a large enough screen or if the screen's too short for bottom navigation.
目前应用程序中已经有了布局。

1.打开 navigation_activity.xmlnavigation_activity.xml (w960dp)

Notice how both layouts contain a NavigationView connected to nav_drawer_menu. In the tablet version (w960dp) the NavigationView is always on screen. On smaller devices the NavigationView is nested within a DrawerLayout.
Now to start implementing the NavigationView navigation.

2.打开MainActivity
3.实现setupNavigationMenu

    private fun setupNavigationMenu(navController: NavController) {
        val sideNavView = findViewById(R.id.nav_view)
        sideNavView?.setupWithNavController(navController)
    }

目前导航菜单就可以使用了,不过暂时和actionbar没有毛关系。
设置ActionBar需要创建一个AppBarConfiguration的实例。

AppBarConfiguration用来配置一些toolbars, collapsing toolbars和action bars的选项。配置选项包括是否bar需要处理抽屉布局,top destination是哪里之类的。

Top-destination是应用中根级别的destination。这种destination在bar中不显示返回按钮,如果destination使用抽屉,那就显示个抽屉按钮呗。

Navigation Architecture Component 3_第1张图片
image.png

4.通过传递top-level destination ids和抽屉布局创建一个 AppBarConfiguration

    val drawerLayout: DrawerLayout? = findViewById(R.id.drawer_layout)
    appBarConfiguration = AppBarConfiguration(setOf(R.id.home_dest, R.id.deeplink_dest), drawerLayout)

How to determine top-level destinations

Destinations reachable via global navigation UI, such as bottom nav or side nav, all appear to users as on the same top level of the hierarchy. Therefore, they are top level destinations. home_dest and deeplink_dest are in the bottom nav and we want the drawer icon to show on both of these destinations, so they are top-level destinations.

Note that the start destination is always considered a top-level destination. If you don't specify a list of top-level destinations, then the only top-level destination is your start destination. You can learn more about AppBarConfiguration in the documentation.

有了AppBarConfiguration,我们现在可以调用 NavigationUI.setupActionBarWithNavController了,它会做以下几件事:

  • 在ActionBar中展示基于destination label的标题

  • 当不处于top-level destination时显示返回按钮

  • 当你处于top-level destination时显示抽屉按钮
    5.实现setupActionBarWithNavController

      private fun setupActionBar(navController: NavController,
                             appBarConfig: AppBarConfiguration) {
          setupActionBarWithNavController(navController, appBarConfig)
      }
    

也需要用NavigationUI处理返回按钮。
6.重写onSupportNavigationUp,调用NavigationUI.navigateUp

override fun onSupportNavigateUp(): Boolean {
    return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}
  1. Run your code. If you open the app in split screen, you should have a working navigation drawer. The up icon and the drawer icon should display at the appropriate times and work correctly.
    Adding new destinations to a NavigationView is easy. Once you have the navigation drawer working with up and back navigation, you just need to add the new menu item.

  2. Open menu/nav_drawer_menu.xml

  3. Add a new menu item for settings_dest

10.Deep Linking to a destination

导航组件也支持deep link。Deep links are a way to jump into the middle of your app's navigation, whether that's from an actual URL link or a pending intent from a notification.

One benefit of using the navigation library to handle deep links is that it ensures users start on the right destination with the appropriate back stack from other entry points such as app widgets, notifications, or web links (covered in the next step).

Navigation提供了NavDeepLinkBuilder类,用来构建一个可以将用户送往指定destination的PendingIntent。

添加一个Deep Link

使用NavDeepLinkBuilder将一个app widget连接到destination。
1.打开DeepLinkAppWidgetProvider
2.添加一个通过NavDeepLinkBuilder构建的PendingIntent

    val pendingIntent = NavDeepLinkBuilder(context)
            .setGraph(R.navigation.mobile_navigation)
            .setDestination(R.id.deeplink_dest)
            .setArguments(args)
            .createPendingIntent()

    remoteViews.setOnClickPendingIntent(R.id.deep_link_button, pendingIntent)

Notice:

  • setGraph 包含导航图
  • setDestination 指定了往哪里连接
  • setArguments 包含了传递给deep link的参数
    NavDeepLinkBuilder默认会打开启动Activity。我们可以将一个Activity作为context或者设置一个明确的Activity类(通过setComponentName())重写这个行为。
    3.添加deep link到屏幕上(添加桌面小组件)。
    4.点它,检查一下destination是否接收了正确的参数。
    Navigation Architecture Component 3_第2张图片
    image.png

    5.看看返回按钮会不会去home_dest。

As a convenience, you can also call NavController's createDeepLink() method to use the Context and current navigation graph from the NavController.

DeepLink Backstack

deep link的backstack是根据传入的导航图确定的。
If the explicit Activity you've chosen has a parent activity, those parent Activities are also included.

The backstack is generated using the destinations specified with app:startDestination. In this app we only have one activity and one level of navigation, so the backstack will take you to the home_dest destination.

More complicated navigation can include nested navigation graphs. The app:startDestination at each level of the nested graphs determines the backstack. For more information on deep links and nested graphs, check out the Principles of Navigation.

你可能感兴趣的:(Navigation Architecture Component 3)