9.使用menus, drawers 和 bottom navigation進(jìn)行導(dǎo)航
NavigationUI and navigation-ui-ktx
導(dǎo)航組件包括一個(gè)NavigationUI和navigation-ui-ktx Kotlin擴(kuò)展。NavigationUI包含有將menu items和destination相關(guān)的靜態(tài)方法,navigation-ui-ktx干一樣的事情,是一堆擴(kuò)展函數(shù)的集合。
如果NavigationUI發(fā)現(xiàn)某個(gè)menu item的ID和導(dǎo)航圖中某個(gè)destination的ID相同,那么就配置為menu item將會(huì)導(dǎo)航到這個(gè)destination。
Using NavigationUI with an Options menu
使用NavigationUI最簡(jiǎn)單的方法是簡(jiǎn)化option menu設(shè)置,特別是簡(jiǎn)化onOptionsItemSelected callback。
1.打開MainActivity
注意這里在onCreateOptionsMenu中已經(jīng)填充了overflow_menu
2.打開overflow_menu.xml
3.擼代碼
<item
android:id="@+id/settings_dest"
android:icon="@drawable/ic_settings"
android:menuCategory="secondary"
android:title="@string/settings" />
4.打開MainActivity
5.讓NavigationUI使用onNavDestinationSelected幫助處理onOptionsItemSelected,如果某個(gè)item不需要進(jìn)行導(dǎo)航,那么用super.onOptionsItemSelected處理就可以。
6.跑起來(lái),就有菜單了。
使用NavigationUI 配置 Bottom Navigation
代碼中已經(jīng)包含了底部導(dǎo)航布局,不過(guò)哪里都不能導(dǎo)航就是了。
1.打開res/layout/navigation_activity/navigation_activity.xml (h470dp),注意看代碼,底部導(dǎo)航欄關(guān)聯(lián)到了bottom_nav_menu.xml
2.打開bottom_nav_menu.xml
菜單中兩個(gè)item的ID已經(jīng)和導(dǎo)航圖中兩個(gè)destination匹配了。
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@id/home_dest"
android:icon="@drawable/ic_home"
android:title="@string/home" />
<item
android:id="@id/deeplink_dest"
android:icon="@drawable/ic_android"
android:title="@string/deeplink" />
</menu>
我們讓底部導(dǎo)航可以整出來(lái)一點(diǎn)事情。
3.打開MainActivity
4.實(shí)現(xiàn)setupBottomNavMenu
private fun setupBottomNavMenu(navController: NavController) {
// TODO STEP 9.3 - Use NavigationUI to set up Bottom Nav
val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
bottomNav?.setupWithNavController(navController)
// TODO END STEP 9.3
}
Using NavigationUI to configure a Navigation Drawer
現(xiàn)在我們來(lái)配置側(cè)邊導(dǎo)航和導(dǎo)航抽屜,包括處理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.
目前應(yīng)用程序中已經(jīng)有了布局。
1.打開 navigation_activity.xml 和navigation_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.實(shí)現(xiàn)setupNavigationMenu
private fun setupNavigationMenu(navController: NavController) {
val sideNavView = findViewById<NavigationView>(R.id.nav_view)
sideNavView?.setupWithNavController(navController)
}
目前導(dǎo)航菜單就可以使用了,不過(guò)暫時(shí)和actionbar沒(méi)有毛關(guān)系。
設(shè)置ActionBar需要?jiǎng)?chuàng)建一個(gè)AppBarConfiguration的實(shí)例。
AppBarConfiguration用來(lái)配置一些toolbars, collapsing toolbars和action bars的選項(xiàng)。配置選項(xiàng)包括是否bar需要處理抽屜布局,top destination是哪里之類的。
Top-destination是應(yīng)用中根級(jí)別的destination。這種destination在bar中不顯示返回按鈕,如果destination使用抽屜,那就顯示個(gè)抽屜按鈕唄。

4.通過(guò)傳遞top-level destination ids和抽屜布局創(chuàng)建一個(gè)
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,我們現(xiàn)在可以調(diào)用 NavigationUI.setupActionBarWithNavController了,它會(huì)做以下幾件事:
在ActionBar中展示基于destination label的標(biāo)題
當(dāng)不處于top-level destination時(shí)顯示返回按鈕
-
當(dāng)你處于top-level destination時(shí)顯示抽屜按鈕
5.實(shí)現(xiàn)setupActionBarWithNavControllerprivate fun setupActionBar(navController: NavController, appBarConfig: AppBarConfiguration) { setupActionBarWithNavController(navController, appBarConfig) }
也需要用NavigationUI處理返回按鈕。
6.重寫onSupportNavigationUp,調(diào)用NavigationUI.navigateUp。
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}
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.Open menu/nav_drawer_menu.xml
Add a new menu item for settings_dest
10.Deep Linking to a destination
導(dǎo)航組件也支持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類,用來(lái)構(gòu)建一個(gè)可以將用戶送往指定destination的PendingIntent。
添加一個(gè)Deep Link
使用NavDeepLinkBuilder將一個(gè)app widget連接到destination。
1.打開DeepLinkAppWidgetProvider
2.添加一個(gè)通過(guò)NavDeepLinkBuilder構(gòu)建的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 包含導(dǎo)航圖
- setDestination 指定了往哪里連接
- setArguments 包含了傳遞給deep link的參數(shù)
NavDeepLinkBuilder默認(rèn)會(huì)打開啟動(dòng)Activity。我們可以將一個(gè)Activity作為context或者設(shè)置一個(gè)明確的Activity類(通過(guò)setComponentName())重寫這個(gè)行為。
3.添加deep link到屏幕上(添加桌面小組件)。
4.點(diǎn)它,檢查一下destination是否接收了正確的參數(shù)。
image.png
5.看看返回按鈕會(huì)不會(huì)去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是根據(jù)傳入的導(dǎo)航圖確定的。
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.
