Navigation 用于 Fragment 的管理。他可以让 Fragrant 之间的切换,拥有像 Activity 间一样的跳转。与 DrawerLayout(抽屉式布局)、ActionBar(导航栏)等有简洁完美的对接。
注意:Navigation 需要在 Android Studio 3.3 或更高版本中才可使用。(并且在 androidx 中支持的更好,之前没有使用 androidx 一直无法添加 Fragment 目的地)
若要在项目中包含导航支持,请将以下依赖项添加到应用程序的 build.gradle 文件中:
dependencies {
def nav_version = "2.1.0-rc01"
// Java
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_dep"
implementation "androidx.navigation:navigation-ui-ktx:$nav_dep"
}
导航图是一个 XML 资源文件,在导航图中有两个概念:
1.Destination:导航图中的每一个导航被称为 Destination (目的地)。
2.Action:导航与导航之间使用 Action (事件) 连接,用于说明两个导航之间的跳转关系。
若要向项目添加导航图,请执行以下操作:
在项目的 res 目录下,新建一个 navigation 文件夹,右键 navigation 文件夹,依次选择:New > Navigation resource file
填写文件名称,如:nav_graph,点击 OK。
在编辑导航图前,需要先创建 Activity,与相关的 Fragment。(此处使用 1 个 Activity,三个 Fragment)
/**
* @Author: Eli Shaw
* @Date: 2019-08-18 10:10:42
* @Description: Activity 容器类
*/
class NavigationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigation)
}
}
/**
* @Author: Eli Shaw
* @Date: 2019-08-18 10:07:13
* @Description: 登录页
*/
class LoginFragment : Fragment(), View.OnClickListener {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val viewRoot = inflater.inflate(R.layout.fragment_login, container, false)
return viewRoot
}
}
/**
* @Author: Eli Shaw
* @Date: 2019-08-18 10:08:52
* @Description: 注册页
*/
class RegisterFragment : Fragment(), View.OnClickListener {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val viewRoot = inflater.inflate(R.layout.fragment_register, container, false)
return viewRoot
}
}
/**
* @Author: Eli Shaw
* @Date: 2019-08-18 10:40:42
* @Description: 首页
*/
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
}
}
创建好 nav_graph 导航图后,双击进行编辑(与常规布局文件很相似)
在 Activity 布局文件中指定导航图的容器
android:name:指定 Fragment 的类型为 NavHostFragment。
app:defaultNavHost="true":让 Navigation 容器处理返回事件,在 Navigation 容器中如果有页面的跳转,点击返回按钮会先处理 容器中 Fragment 页面间的返回,处理完容器中的页面,再处理 Activity 页面的返回。如果值为 false 则直接处理 Activity 页面的返回。
app:navGraph:指定 Navigation 文件。
拖动选中的(目的地)右方的圆点到另一个(目的地)即可创建一个 Action(事件)。
点击左下角的 Text ,将显示如下代码
此图是一个包含导航图的预览页,文本内容如下
导航图使用 NavController 控制(目的地)之间的跳转,在 Activity,Fragment 中获取 NavController 有以下 6 种方式:
1.Fragment.findNavController()
2.View.findNavController()
3.Activity.findNavController(viewId: Int) //只有 Activity 中可以使用
4.NavHostFragment.findNavController(Fragment)
5.Navigation.findNavController(Activity, @IdRes int viewId) //只有 Activity 中可以使用
6.Navigation.findNavController(View)
导航中目的地间也可以使用 Bundle 进行传值
//使用 bundle 传值
val bundle = Bundle()
bundle.putInt(ARG_NAV, navController)
findNavController().navigate(R.id.actionLoginToRegister, bundle)
下面是登录页、注册页完整代码
private const val ARG_NAV = "nav"
/**
* @Author: Eli Shaw
* @Date: 2019-08-18 10:07:13
* @Description: 登录页
*/
class LoginFragment : Fragment(), View.OnClickListener {
private var navController: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
navController = it.getInt(ARG_NAV)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val viewRoot = inflater.inflate(R.layout.fragment_login, container, false)
//注册点击事件
viewRoot.findViewById
private const val ARG_NAV = "nav"
/**
* @Author: Eli Shaw
* @Date: 2019-08-18 10:08:52
* @Description: 注册页
*/
class RegisterFragment : Fragment(), View.OnClickListener {
private var navController: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
navController = it.getInt(ARG_NAV)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val viewRoot = inflater.inflate(R.layout.fragment_register, container, false)
viewRoot.findViewById(R.id.btnBackLogin).setOnClickListener(this)
return viewRoot
}
override fun onClick(view: View) {
val bundle = Bundle()
bundle.putInt(ARG_NAV, navController)
view.findNavController().navigate(R.id.actionRegisterToLogin, bundle)
}
}
自定义转场动画
cut_to_enter.xml (入场动画)
cut_to_exit.xml(出场动画)
在导航图中编辑