一、从零搭建第一个Navigation项目
好,咱们直接动手。这一章我会带你完整创建一个基于Navigation组件的项目。说白了,就是让你亲眼看到Activity、Fragment、NavHostFragment和导航图是怎么串起来的。
我记得刚开始接触Navigation时,总觉得这玩意儿有点玄乎。后来在项目里踩了几次坑,才真正理解它的设计哲学。今天咱们就一步步来,把每个环节都讲透。
1.1 创建Activity——单Activity架构的起点
先创建一个普通的Android项目。我个人习惯用Empty Activity模板,然后把默认的Activity改造成我们的「单Activity容器」。
为什么要单Activity?你想想看,传统的多Activity架构,每个页面切换都要经历Activity生命周期,不仅慢,而且数据传递特别麻烦。Navigation组件就是来解决这个问题的——一个Activity,多个Fragment,通过导航图统一管理。
来看代码:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
嗯,这里要注意:Activity的布局文件里,我们只需要放一个NavHostFragment。它就像个占位符,所有Fragment都会在这个位置切换。
activity_main.xml长这样:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
app:defaultNavHost="true",结果按返回键时Fragment不响应。这个属性告诉系统:当前Activity的返回键由Navigation组件接管。少了它,你的返回逻辑就会出问题。
1.2 创建NavHostFragment——导航的容器
其实上面我们已经把NavHostFragment放进布局了。但这里有个关键点:android:name属性必须写全类名androidx.navigation.fragment.NavHostFragment,不能简写。
NavHostFragment的作用是什么?说白了,它就是一个Fragment的「容器+调度器」。你告诉它要去哪个Fragment,它就帮你执行切换动画、管理返回栈、传递参数。
我个人习惯把NavHostFragment放在布局的最外层,这样整个屏幕都是导航区域。当然你也可以把它放在某个局部区域,实现「页面内嵌导航」的效果。
1.3 创建Fragment——导航的页面单元
接下来创建两个Fragment,作为导航的目标页面。咱们就叫HomeFragment和DetailFragment。
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
}
class DetailFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_detail, container, false)
}
}
每个Fragment对应一个布局文件。这里我建议你给Fragment命名时带上业务含义,别用Fragment1、Fragment2这种名字。我在项目里见过有人这么干,三个月后自己都分不清哪个是哪个。
1.4 编写导航图——串联一切的蓝图
导航图是Navigation组件的核心。它用XML描述所有Fragment之间的跳转关系。你想想看,以前我们写Intent跳转Activity,跳转逻辑散落在各个Activity里。现在好了,所有跳转关系集中在一个文件里管理。
在res/navigation/目录下创建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"
android:id="@+id/nav_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.navigationdemo.HomeFragment"
android:label="首页"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_home_to_detail"
app:destination="@id/detailFragment" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.example.navigationdemo.DetailFragment"
android:label="详情"
tools:layout="@layout/fragment_detail" />
</navigation>
app:startDestination:指定应用启动时默认显示的Fragment。这里设为homeFragment。<action>:定义跳转动作。每个action都有一个唯一id,代码里通过这个id触发跳转。tools:layout:方便在Android Studio的导航编辑器中预览布局。
1.5 在Fragment中触发导航
导航图写好了,怎么在代码里跳转?很简单,通过Navigation.findNavController()获取NavController,然后调用navigate()方法。
class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.btnGoDetail).setOnClickListener {
// 通过导航图定义的action跳转
Navigation.findNavController(it)
.navigate(R.id.action_home_to_detail)
}
}
}
这里有个小细节:findNavController()的参数可以是View,也可以是Fragment。我个人习惯传View,因为View一定在当前的Fragment层级内,不容易出错。
findNavController()找不到NavHostFragment。解决方案是确保调用navigate()的View属于NavHostFragment管理的Fragment层级。
1.6 完整项目结构一览
到这里,一个完整的Navigation项目就搭建好了。咱们用一张图来梳理整个架构:
1.7 运行验证
把项目跑起来,你应该能看到HomeFragment的内容。点击按钮,页面平滑切换到DetailFragment。按返回键,又回到HomeFragment。
这就是Navigation组件最基础的用法。你想想看,整个过程我们只创建了一个Activity,所有页面切换都在Fragment层面完成。这就是单Activity架构的核心思想。
- 一个Activity作为容器,承载所有Fragment
- NavHostFragment是导航的「大脑」,负责Fragment的切换和管理
- 导航图(nav_graph.xml)集中管理所有跳转关系
- 通过
Navigation.findNavController().navigate()触发跳转
嗯,到这里第一个Navigation项目就创建完成了。下一章咱们会深入讲解导航图的更多配置,包括参数传递、动画设置、深层链接等高级用法。但今天先把基础打牢,你亲手敲一遍代码,感受一下Navigation组件带来的便利。
公众号:蓝海资料掘金营,微信deep3321