Jetpack之Navigation

navigation是负责fragment之间切换的处理工具

有三个核心点:

  • Navigation Graph (New XML Resource): 控制中心,包含所有页面及页面间的关系
  • NavHostFragment (Layout XML View):特殊的Fragment,是其他Fragment的“容器”,Navigation Graph中所有Fragmnet正是通过这个特殊的Fragment进行展示的
  • NavController (Kotlin / Java Object): 负责完成Navigation中具体的页面切换工作

三者之间的关系:当需要切换页面时,使用NavController对象,告诉它想要去的Navigation Graph中的哪个Fragment,NavController对象会将目的地的Fragment展示在NavHostFragment中。

一、基本使用

1. 添加依赖

dependencies {
    
    ......
    def nav_version = "2.3.5"

    // Kotlin
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

2. 创建Navigation Graph

res文件夹 -> New -> Android Resource File


Create Navigation Graph

3. 添加NavHostFragmnet

在activity_main.xml文件中添加fragment作为NavHostFragment,其中有三点需要注意:

  • name必须是"androidx.navigation.fragment.NavHostFragment"
  • defaultNavHost设置为"true"
  • navGraph设置为"@navigation/nav_graph"



    


4. 创建Destination

在nav_graph.xml页面里,依次点击加号、 Create new destination创建一个Destination,首次在此创建一个MainFragment作为StartDestination




    

5. 页面切换

在nav_graph.xml页面里,就像创建MainFragment一样创建一个SecondFragment




    
    

5.1 创建Action

在nav_graph.xml页面的Design面板里,单击MainFragment,然后选中右侧的圆圈热点并拖拽指向右侧的SecondFragmnt


选中热点并拖拽

Action创建完成



    
        
    
    

5.2 使用NavController导航到目的地

在fragment_main.xml中添加一个按钮,然后在MainFragment文件中添加该按钮点击事件的监听器,当点击该按钮时通过NavController完成页面跳转

class MainFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById

导航到目的地是使用 NavController 完成的,它是一个在 NavHost 中管理应用导航的对象。每个 NavHost 均有自己的相应NavController,NavController 提供了几种导航到目的地的不同方式,如需从 Fragment、Activity 或View中获取NavController,请使用以下某种方法:

  • Fragment.findNavController()
  • View.findNavController()
  • Activity.findNavController(viewId: Int)

5.3 添加切换动画

在nav_graph.xml页面的Design面板里,点击MainFragment指向SecondFragment的箭头(即页面跳转Action),然后在Attributes面板的Animations部分中,点击要添加的动画旁边的下拉箭头,选择需要设置的动画


添加动画



    

        
    
    

6. 传递参数

6.1 基本类型参数

6.1.1 添加参数

在nav_graph.xml页面的Design面板里,点击接收参数的目的地Fragment(此处为secondFragment), 然后在Attributes面板的Arguments列点击右侧添加按钮(+)可添加参数

添加参数



    

        
    
    
        
    

6.1.2 接收参数
class SecondFragment : Fragment() {
    val TAG = "SecondFragment"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val name = arguments?.getString("name")
        Log.d(TAG, "onCreate() called with: name = $name")
    }

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

logcat 输出:D/SecondFragment: onCreate() called with: name = "HSG"

6.1.3 传递参数
class MainFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById

logcat 输出:D/SecondFragment: onCreate() called with: name = Hello Word

6.2 使用safe args传递参数

该插件可以生成简单的 object和builder类,以便以类型安全的方式浏览和访问任何关联的参数。我们强烈建使用Safe Args进行数据传递,因为它可以确保类型安全。

6.2.1 添加依赖

在project的build.gradle文件中添加safe args插件:

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.3.5"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

在app的build.gradle文件中添加:

(1)如需生成适用于 Java 模块或 Java 和 Kotlin 混合模块的 Java 语言代码,请添加:

apply plugin: "androidx.navigation.safeargs"

(2)如需生成适用于仅 Kotlin 模块的 Kotlin 语言代码,请添加:

apply plugin: "androidx.navigation.safeargs.kotlin"

根据迁移到 AndroidX 文档,gradle.properties 文件中必须具有 android.useAndroidX=true

启用 Safe Args 后,生成的代码会为每个Action(包含发送方和接收方)提供类型安全的类和方法:

  • 为Action的每一个发送方创建一个类。该类的名称是在发送方的名称后面加上“Directions”。例如,如果发送方是名为MainFragment的Fragment,则生成的类的名称为 MainFragmentDirections,该类会为发送方中定义的每个Action提供一个方法。
  • 对于用于传递参数的每个Action,都会创建一个 inner 类,该类的名称根据Action的名称确定。例如,如果Action名称为 action_mainFragment_to_secondFragment,则类名称为 ActionMainFragmentToSecondFragment,可以此关联的 action 类来设置参数值。
  • 为接收目方创建一个类。该类的名称是在接收方的名称后面加上“Args”。例如,如果接收方的 Fragment 的名称为 SecondFragment,则生成的类的名称为 SecondFragmentArgs。可以使用该类的 fromBundle() 方法获取传递的参数。
6.2.2 传递参数
class MainFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById
6.2.3 接收参数
class SecondFragment : Fragment() {
    val TAG = "SecondFragment"
    private val args by navArgs()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        val name = arguments?.getString("name")
        Log.d(TAG, "onCreate() called with: name = ${args.name}")
    }
}

logcat 输出:D/SecondFragment: onCreate() called with: name = Hello Android

7. 配置ActionBar

通过Navigation完成页面跳转已基本完成,但和Activity跳转相比仍有不足之处——当前的ActionBar标题不会跟随Navigation页面变化,而且也没有用于返回的小图标。因此,本节就来解决该问题,Navigation已提供了便捷的解决方案,只需配置NavController对ActionBar进行控制,即可解决该问题。

在MainActivity中,通过四步即可完成配置:
第1步,在Activity上获取NavController

navController = findNavController(R.id.nav_host_fragment)

第2步,配置AppBarConfiguration,以便NavController接管ActionBar后能正确进行控制

appbarConfiguration = AppBarConfiguration.Builder(navController.graph).build()

第3步,配置NavController对ActionBar进行控制

NavigationUI.setupActionBarWithNavController(this, navController, appbarConfiguration)

第4步,让NavController接管返回事件

override fun onSupportNavigateUp(): Boolean {
        return NavigationUI.navigateUp(
            navController,
            appbarConfiguration
        ) or super.onSupportNavigateUp()
    }

完整代码:

class MainActivity : AppCompatActivity() {
    private lateinit var appbarConfiguration: AppBarConfiguration
    private lateinit var navController: NavController

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

        navController = findNavController(R.id.nav_host_fragment)
        appbarConfiguration = AppBarConfiguration.Builder(navController.graph).build()
        NavigationUI.setupActionBarWithNavController(this, navController, appbarConfiguration)
    }

    override fun onSupportNavigateUp(): Boolean {
        return NavigationUI.navigateUp(
            navController,
            appbarConfiguration
        ) or super.onSupportNavigateUp()
    }
}

你可能感兴趣的:(Jetpack之Navigation)