Jetpack之Navigation

1,096 阅读2分钟

作用

统一管理Fragment,管理Ftagment之间跳转和Fragment与Activity的跳转,传参等。在项目中可以用Fragment来替换一部分Activity。

实现效果

tutieshi_590x1280_21s.gif

基本使用

创建导航

右键res文件,new->Android Resource File显示如图

Snipaste_2021-07-20_15-58-25.png type选择Navigation,填入文件名OK就行,会自动生成一个navigation文件夹和一个xml文件

Snipaste_2021-07-20_16-07-33.png 点击 Snipaste_2021-07-20_16-08-11.png 添加已创建的Fragment

Snipaste_2021-07-20_16-10-25.png

点击 Snipaste_2021-07-20_16-12-31.png 设置一个Fragment为主Fragment,再用主Fragment的圆点连接至另一个Fragment表示跳转连接

Snipaste_2021-07-20_16-21-30.png 自动生成的代码

<?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/firstFragment">
    <fragment
        android:id="@+id/firstFragment"
        android:name="com.example.jetpacklearn.FirstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first" >
        <action
            android:id="@+id/action_firstFragment_to_secondFragment"
            app:destination="@id/secondFragment" />
    </fragment>
    <fragment
        android:id="@+id/secondFragment"
        android:name="com.example.jetpacklearn.SecondFragment"
        android:label="second_fragment"
        tools:layout="@layout/second_fragment" />
</navigation>

app:startDestination="@id/firstFragment"表示起始点的Fragment, action中表示要跳转到的Fragment

另外一点,要在承载Fragment的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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView4"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />

</androidx.constraintlayout.widget.ConstraintLayout>

其中android:name="androidx.navigation.fragment.NavHostFragment"是必须的,
app:navGraph="@navigation/nav_graph"为关联之前的导航xml文件
app:defaultNavHost="true"会拦截系统的返回按钮

Fragment跳转与传参

FirstFragment.kt

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val bundleOf = bundleOf("1" to "从First传递过来")
    val str = arguments?.getString("2")
    textView2.text = str

    textView.setOnClickListener {
       findNavController().navigate(R.id.action_firstFragment_to_secondFragment,bundleOf)
    }
}

SecondFragment.kt

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    val str = arguments?.getString("1")
    textView3.text = str

    val bundleOf = bundleOf("2" to "从SecondFragment传递过来")

    textView4.setOnClickListener {
        findNavController().setGraph(R.navigation.nav_graph,bundleOf)
    }

    textView7.setOnClickListener {
        findNavController().navigate(R.id.action_secondFragment_to_secondActivity4)
    }
}

获取NavController的方法
Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int)

从Fragment跳转到Fragment,调用findNavController().navigate(),第一个参数为在导航图中的连接线的action id,第二个参数就是一个包装好的bundle对象。在接收参数的Fragemnt中获取bundle时还是调用getArgument()方法获取。

而Fragment回退时传参就需要调用 findNavController().setGraph(),第一个参数为导航图Navigation的id,第二个参数时bundle对象。如果回退时不需要传参就调用findNavController().navigateUp()就好。

如果需要从Fragment跳转到Activity,还是在导航图中新建一个Activity并用Fragment连线至该Activity,并自动生成action。跳转时还是调用findNavController().navigate()并传入action id。跳转到的Activity需要再用到Fragment的话就再从第一步开始套娃就好。

Snipaste_2021-07-21_17-31-18.png

如果需要从Activity跳转到Activity则无此必要,Navigation也不支持。Navigation本身就是希望用Fragment来代替Activity,如果要这样实现其实用一个Activity创建宿主Fragment再用Fragment来实现跳转一个道理。

另外以我的理解,每个Activty中承载的多个Fragment的导航图都是单独的,也就是一个Activity会对应一个导航图。每个导航图最后目的地大部分也是另一个Activity。