前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Jetpack】Navigation 导航组件 ② ( Navigation 核心要点说明 | 创建 Navigation Graph | 创建 NavHostFragment | 完整代码示例 )

【Jetpack】Navigation 导航组件 ② ( Navigation 核心要点说明 | 创建 Navigation Graph | 创建 NavHostFragment | 完整代码示例 )

作者头像
韩曙亮
发布2023-10-11 18:29:59
3080
发布2023-10-11 18:29:59
举报
代码地址 :

一、Navigation 导航组件开发核心要点说明

1、Navigation 各子部件的创建顺序

Navigation 导航组件各子部件的创建顺序要点如下 :

  • 首先 , 创建被导航的 Fragment 页面代码 和 对应的布局文件 ;
  • 然后 , 基于创建的 Fragment 创建对应的 Navigation Graph , 在其中配置 Fragment 之间的跳转动作 ;
  • 再后 , 基于创建的 Navigation Graph 创建显示内容的 NavHostFragment 组件 ;
  • 最后 , 在 Activity 中 获取 NavController 组件实现 Fragment 之间的跳转 ;

必须按照上述流程进行创建 : Fragment -> Navigation Graph -> NavHostFragment -> NavController , 后面的组件依赖于前面的组件 , 否则无法实现 Navigation 导航 ;

2、导入 Navigation 依赖

使用 Navigation 组件 , 必须导入 Navigation 依赖 , 不同的开发语言导入不同的依赖 :

  • 使用 Java 语言 开发 Navigation 导航 , 导入如下依赖 :
代码语言:javascript
复制
dependencies {  
    implementation 'androidx.navigation:navigation-fragment:2.2.2'
    implementation 'androidx.navigation:navigation-ui:2.2.2'
}
  • 使用 Kotlin 语言 开发 Navigation 导航 , 导入如下依赖 :
代码语言:javascript
复制
dependencies {  
    implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'  
    implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'  
}

如果不导入依赖 , 直接使用 Navigation , 会报出 " failed to add navigation dependency " 异常信息 ;

3、创建 Fragment 及布局文件

右键点击 要创建 Fragment 的代码 Package 包 , 选择 " New / Fragment / Fragment (Blank) " 选项 , 就可以直接 创建一个 Fragment , 同时会生成对应的 Fragment 布局文件 ;

在这里插入图片描述
在这里插入图片描述

4、创建 Navigation Graph

右键点击 res 资源目录 , 在弹出的下拉菜单中 , 选择 " New / Android Resource File " 选项 ,

在这里插入图片描述
在这里插入图片描述

在 " Resource Type " 选项处 , 选择 " Navigation " 选项 , 选择后 " Root element " 和 " Directory name " 选项会被自动设置 , 开发者只需要设置一个 " File name " 即可 ;

在这里插入图片描述
在这里插入图片描述

创建 Navigation Graph 时 , 需要指定要将哪些 Fragment 纳入导航管理 , 这也是要先创建 Fragment , 然后才能创建 Navigation Graph 的原因 ;

创建完 Navigation Graph 后 , 在 Design 模式下 , 点击 " New Destination " 按钮 , 添加要进行导航的 Fragment 页面 , 这里将 FragmentA 和 FragmentB 都纳入到 Navigation 导航管理中 ;

在这里插入图片描述
在这里插入图片描述

创建后可以通过拖动鼠标 , 设置 Navigation Graph 中两个 Fragment 之间的跳转关系 , FragmentA 跳转到 FragmentB , FragmentB 跳转到 FragmentA ;

在这里插入图片描述
在这里插入图片描述

这样就完成了 Navigation Graph 的创建 , 之后会通过 NavController 调用上面的两个跳转 , 分别实现两个 Fragment 之间的跳转 ;

5、创建 NavHostFragment

NavHostFragment 设置在 Activity 的布局文件中 , 一般是为 <fragment/>标签设置一个 android:name="androidx.navigation.fragment.NavHostFragment" 属性 , 该 fragment 就成为了 NavHostFragment ;

代码语言:javascript
复制
    <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:navGraph="@navigation/navigation_graph" />

这里不建议在 Design 图形化界面中拖动 Container 下的 NavHostFragment 到布局中 , 生成的代码是错误的 ;

具体出错的内容在错误记录专栏有详细分析 , 这里不再赘述 ;

在这里插入图片描述
在这里插入图片描述

6、创建 NavController

在 Activity 中通过 调用 findNavController 函数 , 获取 NavController , 然后通过该 NavController 变量进行导航 ;

fragmentContainerView 组件的 管理 操作通过 NavController 完成 ;

代码语言:javascript
复制
        // fragmentContainerView 组件的 管理 操作通过 NavController 完成
        // 对应的就是 navController 实例变量
        val navController = findNavController(this, R.id.fragment)
        NavigationUI.setupActionBarWithNavController(this, navController)

7、Fragment 实现导航操作

在 Fragment 界面中 , 通过点击按钮 , 跳转到另外一个 Fragment 界面 ;

首先 , 获取 NavigationController , 通过调用 Navigation.findNavController 函数 , 即可获取 NavigationController 实例对象 ;

然后 , 调用 NavigationController#navigate 进行导航 , 传入 Navigation Graph 中具体的 action 的 id 即可 ;

代码语言:javascript
复制
            // 获取 NavigationController
            val navController = Navigation.findNavController(it)
            // 按照 action_fragmentA_to_fragmentB 对应的 action 的导航路线走
            navController.navigate(R.id.action_fragmentA_to_fragmentB)

上述代码中 R.id.action_fragmentA_to_fragmentB 对应的 action 如下 :

代码语言:javascript
复制
    <fragment
        android:id="@+id/fragmentA"
        android:name="kim.hsl.nav.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >
        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB" />
    </fragment>

二、Navigation 导航组件完整代码示例


代码地址 :

1、Fragment 完整源码

创建 2 个 Fragment , 每个 Fragment 都设置一个按钮 , 两个 Fragment 之间互相跳转 ;

FragmentA 源码

Fragment 中核心的跳转源码如下 , 先获取 NavigationController , 然后调用 NavigationController#navigate 跳转到 FragmentB 页面 ;

代码语言:javascript
复制
            // 获取 NavigationController
            val navController = Navigation.findNavController(it)
            // 按照 action_fragmentA_to_fragmentB 对应的 action 的导航路线走
            navController.navigate(R.id.action_fragmentA_to_fragmentB)

完整源码 :

代码语言:javascript
复制
package kim.hsl.nav

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import androidx.navigation.Navigation.findNavController

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [FragmentA.newInstance] factory method to
 * create an instance of this fragment.
 */
class FragmentA : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_a, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment FragmentA.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            FragmentA().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val button = view.findViewById<Button>(R.id.button)
        button.setOnClickListener {
            // 获取 NavigationController
            val navController = Navigation.findNavController(it)
            // 按照 action_fragmentA_to_fragmentB 对应的 action 的导航路线走
            navController.navigate(R.id.action_fragmentA_to_fragmentB)
        }
    }
}
FragmentA 布局文件
代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FragmentA">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="跳转到 B"
        android:onClick="onClick" />

</FrameLayout>
FragmentB 源码

Fragment 中核心的跳转源码如下 , 先获取 NavigationController , 然后调用 NavigationController#navigate 跳转到 FragmentB 页面 ;

代码语言:javascript
复制
            // 获取 NavigationController
            val navController = Navigation.findNavController(it)
            // 按照 action_fragmentB_to_fragmentA 对应的 action 的导航路线走
            navController.navigate(R.id.action_fragmentB_to_fragmentA)

完整代码如下 :

代码语言:javascript
复制
package kim.hsl.nav

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.navigation.Navigation

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [FragmentB.newInstance] factory method to
 * create an instance of this fragment.
 */
class FragmentB : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_b, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment FragmentB.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            FragmentB().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val button = view.findViewById<Button>(R.id.button)
        button.setOnClickListener {
            // 获取 NavigationController
            val navController = Navigation.findNavController(it)
            // 按照 action_fragmentB_to_fragmentA 对应的 action 的导航路线走
            navController.navigate(R.id.action_fragmentB_to_fragmentA)
        }
    }
}
FragmentB 布局文件
代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FragmentB">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="跳转到 A"
        android:onClick="onClick" />

</FrameLayout>

2、Navigation Graph 源码

创建 Navigation Graph , 导入两个 Fragment , 并设置 Navigation Graph 中两个 Fragment 之间的跳转关系 , FragmentA 跳转到 FragmentB , FragmentB 跳转到 FragmentA ;

代码语言:javascript
复制
<?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/navigation_graph"
    app:startDestination="@id/fragmentA">

    <fragment
        android:id="@+id/fragmentA"
        android:name="kim.hsl.nav.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >
        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB" />
    </fragment>
    <fragment
        android:id="@+id/fragmentB"
        android:name="kim.hsl.nav.FragmentB"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" >
        <action
            android:id="@+id/action_fragmentB_to_fragmentA"
            app:destination="@id/fragmentA" />
    </fragment>
</navigation>

3、Activity 布局文件中添加 NavHostFragment 组件

NavHostFragment 设置在 Activity 的布局文件中 , 一般是为 <fragment/>标签设置一个 android:name="androidx.navigation.fragment.NavHostFragment" 属性 , 该 fragment 就成为了 NavHostFragment ;

代码语言:javascript
复制
    <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:navGraph="@navigation/navigation_graph" />

完整布局文件代码如下 :

代码语言:javascript
复制
<?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">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <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:navGraph="@navigation/navigation_graph" />

</androidx.constraintlayout.widget.ConstraintLayout>

4、Activity 代码中获取 NavController 并进行导航

在 Activity 中通过 调用 findNavController 函数 , 获取 NavController , 然后通过该 NavController 变量进行导航 ;

fragmentContainerView 组件的 管理 操作通过 NavController 完成 ;

代码语言:javascript
复制
        // fragmentContainerView 组件的 管理 操作通过 NavController 完成
        // 对应的就是 navController 实例变量
        val navController = findNavController(this, R.id.fragment)
        NavigationUI.setupActionBarWithNavController(this, navController)

完整代码如下 :

代码语言:javascript
复制
package kim.hsl.nav

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.Navigation.findNavController
import androidx.navigation.ui.NavigationUI

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // fragmentContainerView 组件的 管理 操作通过 NavController 完成
        // 对应的就是 navController 实例变量
        val navController = findNavController(this, R.id.fragment)
        NavigationUI.setupActionBarWithNavController(this, navController)
    }
}

5、运行效果

在 FragmentA 页面点击按钮 , 跳转到 FragmentB 页面 , 在 FragmentB 页面点击按钮 , 跳转到 FragmentA 页面 ;

请添加图片描述
请添加图片描述

代码地址 :

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代码地址 :
  • 一、Navigation 导航组件开发核心要点说明
    • 1、Navigation 各子部件的创建顺序
      • 2、导入 Navigation 依赖
        • 3、创建 Fragment 及布局文件
          • 4、创建 Navigation Graph
            • 5、创建 NavHostFragment
              • 6、创建 NavController
                • 7、Fragment 实现导航操作
                • 二、Navigation 导航组件完整代码示例
                  • 1、Fragment 完整源码
                    • FragmentA 源码
                    • FragmentA 布局文件
                    • FragmentB 源码
                    • FragmentB 布局文件
                  • 2、Navigation Graph 源码
                    • 3、Activity 布局文件中添加 NavHostFragment 组件
                      • 4、Activity 代码中获取 NavController 并进行导航
                        • 5、运行效果
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档