Jetpack 系列 (一) — Navigation
exit = R.anim.slide_out_leftpopEnter = R.anim.slide_in_leftpopExit = R.anim.slide_out_right}}
val flowStepNumber = 1val product = Product("可乐")val directions = HomeFragmentDirections.nextAction(flowStepNumber, product)findNavController().navigate(directions, options)
菜单跳转
NavigationUI
具有将菜单项与导航目的地相关联的静态方法,navigation-ui-ktx
是执行关联操作的一组扩展函数。如果 NavigationUI
在当前导航图上找到与目的地具有相同 ID 的菜单项,就会将该菜单项配置为导航到该目的地。
步骤一: 创建 menu 文件 overflow_menu.xml
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/settings_dest"android:icon="@drawable/ic_settings"android:menuCategory="secondary"android:title="@string/settings" /></menu>
步骤二: 添加 menu 到菜单,添加选中事件
// 添加 menu 到菜单 override fun onCreateOptionsMenu(menu: Menu?): Boolean {menuInflater.inflate(R.menu.overflow_menu, menu)return true}
// menu 选中 override fun onOptionsItemSelected(item: MenuItem): Boolean {return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))|| super.onOptionsItemSelected(item)}
步骤三: 修改 Graph 文件,注意 id 和 menu 文件保持一致,这里我特意把目的地设为 activity,因为我最先误解只能是 fragment
<activityandroid:id="@+id/settings_dest"android:name="com.hxdi.myapplication.SettingActivity"android:label="activity_seting"tools:layout="@layout/activity_seting" />
底部 Bottom
步骤一: 添加 BottomNavigationView
<com.google.android.material.bottomnavigation.BottomNavigationViewandroid:id="@+id/bottom_nav_view"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:menu="@menu/bottom_nav_menu"/>
步骤二: 编写 menu, bottom_nav_menu.xml
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@id/home_dest"android:icon="@drawable/ic_home"android:title="@string/home" /><itemandroid:id="@id/deeplink_dest"android:icon="@drawable/ic_android"android:title="@string/deeplink" /></menu>
步骤三: 关联 NavController
// 底部 Bottomprivate fun setupBottomNavMenu(navController: NavController) {binding.bottomNavView.setupWithNavController(navController)}
步骤四: 设置顶级界面,
appBarConfiguration = AppBarConfiguration(setOf(R.id.home_dest, R.id.deeplink_dest) // 顶级目的地)setupActionBar(navController, appBarConfiguration)
侧边 DrawLayout
步骤一:添加 NavigationView
<androidx.drawerlayout.widget.DrawerLayoutxmlns: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:layout_width="match_parent"android:layout_height="match_parent">
...
<com.google.android.material.navigation.NavigationViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:layout_gravity="start"app:menu="@menu/nav_drawer_menu"/></androidx.drawerlayout.widget.DrawerLayout>
步骤二: 编写 menu,nav_drawer_menu.xml,同上, 略
步骤二: 关联 NavController
appBarConfiguration = AppBarConfiguration(setOf(R.id.home_dest, R.id.deeplink_dest), // 顶级目的地 binding.drawerLayout // DrawerLayout)
桌面小插件
这一小节的功能是通过桌面插件跳转至 App 某个页面
步骤一: 通过 AppWidgetProvider 创建桌面插件,AppWidgetProvider 实质是 BroadcastReceiver
class DeepLinkAppWidgetProvider : AppWidgetProvider() {
override fun onUpdate(context: Context,appWidgetManager: AppWidgetManager,appWidgetIds: IntArray) {val remoteViews = RemoteViews(context.packageName,R.layout.deep_link_appwidget)val args = Bundle()args.putString("myarg", "From 桌面")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)
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews)}}
步骤二: AppWidgetProvider 实质是 BroadcastReceiver,在配置文件当中注册
<receiver android:name=".DeepLinkAppWidgetProvider"><intent-filter><action android:name="android.appwidget.action.APPWIDG
ET_UPDATE" /></intent-filter>
<meta-dataandroid:name="android.appwidget.provider"android:resource="@xml/deep_link_appwidget_info" /></receiver>
步骤三: 为了观察效果,接受方也要处理一下
val myArg = arguments?.getString("myarg")binding.text.text = myArg
网页链接跳转
NavController 支持将网址直接映射到导航图中的目的地。
步骤一: 在目的地添加
<fragmentandroid:id="@+id/deeplink_dest"android:name="com.hxdi.myapplication.DeepLinkFragment"android:label="@string/deeplink"tools:layout="@layout/fragment_deep_link">
<argumentandroid:name="myarg"android:defaultValue="Android!"/>
<deepLink app:uri="www.example.com/{myarg}" />
</fragment>
步骤二: 修改配置文件, 添加 nav-graph
<activityandroid:name=".MainActivity"android:launchMode="singleTask"><intent-filter><action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /></intent-filter><nav-graph android:value="@navigation/mobile_navigation" /></activity>
通知栏跳转
本来以为到这里就结束了,但是发现例子当中还有一个通知跳转,索性也写一下,顺便复习一下通知的写法: 创建通知,NotificationManager =》 检测版本 =》 Andorid 8 以上 创建通道 =》notify
binding.button.setOnClickListener {val etArg = binding.etArg.text.toString()val args = Bundle()args.putString("myarg", etArg)
val deepLink = findNavController().createDeepLink().setDestination(R.id.deeplink_dest).setArguments(args).createPendingIntent()
val notificationManager =context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManagerif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {notificationManager.createNotificationChannel(NotificationChannel("deepLink","消息",NotificationManager.IMPORTANCE_HIGH))}
val notification = NotificationCompat.Builder(requireContext(), "deepLink").setContentTitle("Navigation").setContentText("Deep link to Android").setSmallIcon(R.drawable.ic_android).setContentIntent(deepLink).setAutoCancel(true).build()
notificationManager.notify(0, notification)}
相关知识点
知识点一: actionBar 绑定
要想 lable 显示 Graph 文件当中配置的文字,以及 actionBar 和 NavController 关联起来,需要如下步骤
// 步骤一 显示 ActionBarsetSupportActionBar(binding.toolbar)
// 步骤二 找到 NavHostFragmentval host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragmentval navController = host.navController
// 步骤三 关联 NavController 和 AppBarConfigurationappBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration)
知识点二: 点击事件
语法层面上方式二和方式一三相同,但是 actionId 只使用于方式二,这个
createNavigateOnClickListener()
内部创建 View 点击事件有关
// 跳转方式二 actionIdbinding.button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_action))binding.button.setOnClickListener {// 跳转方式一 idfindNavController().navigate(R.id.flow_step_fragment, null)// 跳转方式三 actionval directions = HomeFragmentDirections.nextAction()findNavController().navigate(directions)}
知识点三:路由监听
NavController
提供了全局的监听接口
// NavController 提供了全局的监听接口 navController.addOnDestinationChangedListener { controller, destination, arguments ->val dest: String = try {resources.getResourceName(destination.id)} catch (e: Resources.NotFoundException) {destination.id.toString()}Log.d("NavigationActivity", "Navigated to $dest")}
评论