Android Jetpack学习之旅--> Navigation 的使用

Posted Kevin-Dev

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack学习之旅--> Navigation 的使用相关的知识,希望对你有一定的参考价值。

简介

1. 定义
Navigation 是一个可简化 android 导航的库和插件;更确切的来说,Navigation是用来管理 Fragment 的切换,并且可以通过可视化的方式,看见 App 的交互流程。这完美的契合了 Jake Wharton 大神单 Activity 的建议。

2. 优点

  • 处理 Fragment 的切换
  • 默认情况下正确处理 Fragment 的前进和后退
  • 为过渡和动画提供标准化的资源
  • 实现和处理深层连接
  • 可以绑定 ToolbarBottomNavigationViewActionBar
  • SafeArgs(Gradle插件) 数据传递时提供类型安全性
  • ViewModel 支持

3. 前期准备
Android studio 版本需要 3.2+

4. 学习资料

实践

0. 效果图

1. 添加依赖
在根目录的 build.gradle 添加:

buildscript 
    ext 
        kotlinVersion = '1.6.10'
        appCompatVersion = "1.4.0"
        recyclerVersion = "1.2.1"
        materialVersion = "1.4.0"
        navigationVersion = "2.3.5"
        constraintLayoutVersion = "2.1.2"
    

    dependencies 
        classpath 'com.android.tools.build:gradle:7.0.4'
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"

    

app/build.gradle 添加:

plugins 
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'androidx.navigation.safeargs.kotlin'

dependencies 
    ...
    //Navigation
    implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion"
    implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion"


2. 创建 navigation 导航
创建基础目录:资源文件 res 目录下创建 navigation 目录 -> 右击 navigation 目录 New 一个Navigation resource file

<?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/login_navigation"
	app:startDestination="@id/welcome">


	<fragment
		android:id="@+id/login"
		android:name="com.hkt.navigationapp.LoginFragment"
		android:label="LoginFragment"
		tools:layout="@layout/login_fragment"
		/>

	<fragment
		android:id="@+id/welcome"
		android:name="com.hkt.navigationapp.WelcomeFragment"
		android:label="LoginFragment"
		tools:layout="@layout/welcome_fragment">
		<action
			android:id="@+id/action_welcome_to_login"
			app:destination="@id/login"/>
		<action
			android:id="@+id/action_welcome_to_register"
			app:enterAnim="@anim/common_slide_in_right"
			app:exitAnim="@anim/common_slide_out_left"
			app:popEnterAnim="@anim/common_slide_in_left"
			app:popExitAnim="@anim/common_slide_out_right"
			app:destination="@id/register"/>
	</fragment>

	<fragment
		android:id="@+id/register"
		android:name="com.hkt.navigationapp.RegisterFragment"
		android:label="LoginFragment"
		tools:layout="@layout/register_fragment"
		>

		<argument
			android:name="EMAIL"
			android:defaultValue="2005@qq.com"
			app:argType="string"/>
	</fragment>
</navigation>

创建一个 Destination,如果说 navigation是我们的导航工具,Destination 是我们的目的地,在此之前,我已经写好了一个 WelcomeFragmentLoginFragmentRegisterFragment,添加Destination 的操作完成后如下所示

3. 建立 NavHostFragment
我们创建一个新的 LoginActivity,在 activity_login.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=".LoginActivity">

    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/login_navigation"
        app:defaultNavHost="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

4. 界面跳转、参数传递和动画
WelcomeFragment 中,点击登录和注册按钮可以分别跳转到 LoginFragmentRegisterFragment 中。

方式一 利用 ID 导航
目标:WelcomeFragment 携带 keyname 的数据跳转到 LoginFragmentLoginFragment 接收后显示。
Have a account ? Login 按钮的点击事件如下:

btnLogin.setOnClickListener 
            // 设置动画参数
            val navOption = navOptions 
                anim 
                    enter = R.anim.common_slide_in_right
                    exit = R.anim.common_slide_out_left
                    popEnter = R.anim.common_slide_in_left
                    popExit = R.anim.common_slide_out_right
                
            

            val name = AppPrefsUtils.getString(BaseConstant.SP_USER_NAME)
            // Navigation 传递参数
            val bundle = Bundle()
            bundle.putString(BaseConstant.ARGS_NAME,name)
            findNavController().navigate(R.id.login, bundle,navOption)
        

方式二 利用 Safe Args
目标:WelcomeFragment 通过 Safe Args 将数据传到 RegisterFragmentRegisterFragment 接收后显示。
再看一下已经展示过的 login_navigation.xml

<navigation
    ...>

    <fragment
        ...
        />

    <fragment
        android:id="@+id/welcome"
        >
        <action
            android:id="@+id/action_welcome_to_login"
            app:destination="@id/login"/>
        <action
            android:id="@+id/action_welcome_to_register"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right"
            app:destination="@id/register"/>
    </fragment>

    <fragment
        android:id="@+id/register"
        ...
        >

        <argument
            android:name="EMAIL"
            android:defaultValue="2005@qq.com"
            app:argType="string"/>
    </fragment>
</navigation>

5. 更多
Navigation 可以绑定 menusdrawersbottom navigation,这里我们以 bottom navigation 为例,我先在 navigation 目录下新创建了 main_navigation.xml,接着新建了 MainActivity,下面则是activity_main.xml:

<LinearLayout
    ...>

    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        app:navGraph="@navigation/main_navigation"
        app:defaultNavHost="true"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/navigation_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        app:itemIconTint="@color/colorAccent"
        app:itemTextColor="@color/colorPrimary"
        app:menu="@menu/menu_main"/>

</LinearLayout>

MainActivity 中的处理也十分简单:

class MainActivity : AppCompatActivity() 

    lateinit var bottomNavigationView: BottomNavigationView

    override fun onCreate(savedInstanceState: Bundle?) 
        //...
        val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
        val navController = host.navController
        initWidget()
        initBottomNavigationView(bottomNavigationView,navController)
    

    private fun initBottomNavigationView(bottomNavigationView: BottomNavigationView, navController: NavController) 
        bottomNavigationView.setupWithNavController(navController)
    

    private fun initWidget() 
        bottomNavigationView = findViewById(R.id.navigation_view)
    

效果:

小结

以上是关于Android Jetpack学习之旅--> Navigation 的使用的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack 学习之旅--> Data Binding 的使用

Android Jetpack学习之旅--> Navigation 的使用

Android Jetpack 学习之旅--> ViewModel & LiveData 的使用

Android Jetpack 学习之旅--> Room 的使用

Lifecycle原理分析 ——《Android打怪升级之旅》

03Lifecycle源码分析 ——《Android打怪升级之旅》