Navigation
Navigation是google官方新增的用于Fragment管理的一个架构组件,可以很方便的像管理Activity一样管理你的Fragment,并且google在AndroidStudio3.2中加入了可视化手动拖拽式的组件
基本概念
- App - 一个页面栈结构
- Destination - 一个页面的子页面,通常是一个Fragment,但也支持其他类型
- Activity
- 其他NavigationGraph
- 自定义Destination
- Deep-Link - 链接形式的跳转(URI形式的链接)
- NavigationGraph - 一组Destination构成的页面结构(一个Navigation xml文件表示)
- Actions - 连接不同Destination的行为
Navigation的编写原则
- 每个App必须有个固定的起点,对应的,每个Activity中也需要有个固定的起点Fragment
- 使用Stack结构来管理Navigation状态,起始页面在Stack底部,当前页面在Stack的top,在Navigation中使用destination来描述一个页面,可以是Activity也可以是Fragment
- 开始destination不显示上一页按钮,如果是从其他App页面通过
deep-link
(下面会讲到)导航过来的,按上一页返回的是父级页面而不是其他App - Back和Up(上一页)在大部分情况下是等同的,除非Back按钮按下后会使得App退出
- Deep-link 和 普通Navigation 跳转形成的页面栈应该是一样的
Navigation简单例子的编写步骤
1.有一个Activity,在layout文件中声明一个fragment
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.apm29.yjw.demo.ui.main.MainActivity">
<fragment
android:layout_width="match_parent"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/main_nav_graph"
app:defaultNavHost="true"
android:layout_height="match_parent"/>
</FrameLayout>
- app:defaultNavHost="true" 表示使用默认的导航host,自动覆盖Activity的back按
钮,不用再覆写[AppCompatActivity.onSupportNavigateUp()
]
(https://developer.android.google.cn/reference/android/support/v7/app/AppCompatActivity)方法 - app:navGraph="@navigation/main_nav_graph"指向你的nav_graph文件
当然Navigation也提供了代码式的引入形式
val finalHost = NavHostFragment.create(R.navigation.main_nav_graph)
supportFragmentManager.beginTransaction()
.replace(R.id.nav_host, finalHost)
.setPrimaryNavigationFragment(finalHost) // this is the equivalent to app:defaultNavHost="true"
.commit()
2.编写main_nav_graph.xml文件(文件名自己定义)
<?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"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.apm29.yjw.demo.ui.main.MainFragment"
android:label="MainFragment">
<action
android:id="@+id/action_mainFragment_to_mainDetailFragment"
app:destination="@id/mainDetailFragment" />
</fragment>
<fragment
android:id="@+id/mainDetailFragment"
android:name="com.apm29.yjw.demo.ui.main.MainDetailFragment"
android:label="MainDetailFragment">
<argument android:name="id"
app:argType="String"
android:defaultValue="0"/>
<deepLink
android:autoVerify="true"
app:uri="www.main.detail/{id}" />
</fragment>
</navigation>
- app:startDestination="@id/mainFragment" 指定初始页面
- fragment节点表示一个destination
- name属性指定Fragment的全路径名
- label是在可视化界面的显示名称
- action标签定义了Destination之间的跳转行为
- 将Navigation绑定到UI组件
其中有一个关键的类
NavController
,通过以下方法得到其实例
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
然后使用它的navigate
方法导航到你想去的Destination,接收参数可以是一个ActionId(定义在nav_graph文件中的),使用navigateUp
,popBackStack
对应Up和Back按键,另外还可以加入Bundle,NavOption,ShareElements等,参考https://developer.android.google.cn/topic/libraries/architecture/navigation/navigation-implementing#Create-transition
// Rename the Pair class from the Android framework to avoid a name clash
import android.util.Pair as UtilPair
...
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
UtilPair.create(imageView, "header_image"),
UtilPair.create(titleView, "header_title"))
val extras = ActivityNavigator.Extras(options)
view.findNavController().navigate(R.id.details,
null, // Bundle of args
null, // NavOptions
extras)
使用SharedElement
val extras = FragmentNavigatorExtras(
imageView to "header_image",
titleView to "header_title")
view.findNavController().navigate(R.id.confirmationAction,
null, // Bundle of args
null, // NavOptions
extras)
先给navigate()方法添加extra参数,包含了一些<View,String>的Pair,View表示sharedElement,String则是transitionName,可以在xml中确定也可以代码确定
<ImageView
android:transitionName="@string/app_icon"
android:id="@+id/imageView"
app:srcCompat="@mipmap/ic_launcher_round" />
imageView.transitionName = getString(R.string.app_icon)
然后再设置Fragment中的SharedElementReturnTransition和SharedElementEnterTransition
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
sharedElementReturnTransition = AutoTransition()
sharedElementEnterTransition = AutoTransition()
}
实际上Navigation 1.0.0 alpha06才加入的这个功能,并不是很完善,只为我们完成了SharedELement的添加,剩余工作还是我们自己完成