Navigation

发布时间 2023-04-23 18:29:59作者: ZZX11
Navigation

image-20230423145633477

以下代码都可以通过拖拽生成

<?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/fragmentA">

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.example.testnavigation.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >
        <action
            android:id="@+id/action_fragmentA_to_fragmentB2"
            app:destination="@id/fragmentB" />
    </fragment>
    <fragment
        android:id="@+id/fragmentB"
        android:name="com.example.testnavigation.FragmentB"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" >
        <action
            android:id="@+id/action_fragmentB_to_fragmentC2"
            app:destination="@id/fragmentC" />
    </fragment>
    <fragment
        android:id="@+id/fragmentC"
        android:name="com.example.testnavigation.FragmentC"
        android:label="fragment_c"
        tools:layout="@layout/fragment_c" />
</navigation>

navigation是根标签,通过startDestination配置默认启动的第一个页面,这里配置的是FragmentA
fragment标签代表一个fragment,其实这里不仅可以配置fragment,也可以配置activity,甚至还可以自定义
action标签定义了页面跳转的行为,相当于上图中的每条线,destination定义跳转的目标页,还可以定义跳转时的动画等等
当调用到 action_FragmentA_to_FragmentB2 这个 action,会从 FragmentA -> FragmentB

一种特殊的Fragment,用于承载导航内容的容器,存放在activity中

<?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">

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

</androidx.constraintlayout.widget.ConstraintLayout>

android:name指定NavHostFragment
app:navGraph指定导航视图,即建好的nav_graph.xml
app:defaultNavHost=true意思是可以拦截系统的返回键,可以理解为默认给fragment实现了返回键的功能,这样在fragment的跳转过程中,当我们按返回键时,就可以使得fragment跟activity一样可以回到上一个页面了

通过NavController 管理fragment之间的跳转

打开FragmentA类,给布局中的TextView定义一个点击事件

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    tv.setOnClickListener {
        val navController = Navigation.findNavController(it)
        navController.navigate(R.id.action_fragmentA_to_fragmentB2)
    }
}

可以看到,通过navController管理fragment的跳转非常简单,首先得到navController对象,然后调用它的navigate方法,传入前面nav_graph中定义的action的id即可。

按同样的方法给FragmentB中的TextView也设置一个点击事件,使得点击时跳转到FragmentC

运行程序,FragmentA -> FragmentB -> FragmentC,此时按返回键,也是一个一个页面返回,如果把前面的app:defaultNavHost设置为false,按返回键后会发现直接返回到桌面。

在这里插入图片描述

app:defaultNavHost="true"属性可以确保NavHostFragment可以拦截系统的回退事件。你也可以重写AppCompatActivity.onSupportNavigateUp()方法并且调用NavController.navigateUp方法:
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setupActionBarWithNavController(findNavController(R.id.fcv))
 
 
    }
 
    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.fcv)
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
}

跳转时通过 safeArgs 插件传递参数

这部分无所谓,直接使用bundle就行了

safeArgs会根据nav_graph中的fragment标签生成对应的类,

  • action标签会以“类名+Directions”命名,
  • argument标签会以“类名+Args”命名

从home->detail

image-20230423154335357

build 自动生成代码

接下来在Home_Fragment中

image-20230423154429899

在Deatil中

image-20230423154519600

注意Menu中的id要和Navigation Graph中的id相对应

image-20230423173427969

在MainActivity中

image-20230423173749452

image-20230423173840357

跳转后去掉导航栏,在对应的fragment中

image-20230423174043532

最后在MainActivity中对页面的切换完成进行监听设置(addOnDestinationChangedListener)

image-20230423174141359

该部分还可参考

https://blog.csdn.net/stephen_sun_/article/details/123716172?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168224198216800188586277%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168224198216800188586277&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-123716172-null-null.142^v86^insert_down1,239^v2^insert_chatgpt&utm_term=NavigationUI&spm=1018.2226.3001.4187

https://blog.csdn.net/qq_44408913/article/details/109076226

https://blog.csdn.net/qq_43404873/article/details/109515441

Reference:

https://blog.csdn.net/JMW1407/article/details/125714708

https://www.bilibili.com/video/BV1Ry4y1t7Tj?p=26&spm_id_from=pageDriver&vd_source=5e78312fb5f90b9c83a318189a70a5c0

https://blog.csdn.net/mp624183768/article/details/126338041?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168223426716800182135271%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168223426716800182135271&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-126338041-null-null.142v86insert_down1,239v2insert_chatgpt&utm_term=navigateUp&spm=1018.2226.3001.4187

https://www.bilibili.com/video/BV1ma411R79w/?vd_source=5e78312fb5f90b9c83a318189a70a5c0