乐趣区

关于android:Navigation-这么好用的导航框架你确定不来看看

前言

🏀什么是 Navigation?官网文档的话有点不容易让人了解。所以,这里用我本人的话来总结一下,咱们在解决 Fragment 是须要通过写 Fragment 的事务去操作 Fragment 的,而 Navigation 的呈现是为了解决咱们之前开发的一些痛点。Navigation 次要用于实现 Fragment 代替 Activity 的页面导航性能,让 Fragment 可能轻松的实现跳转与传递参数,咱们能够通过应用 Navigation,让 Fragment 代替 android 我的项目中绝大多数的 Activity。但须要留神的是在应用 Navigation 切换页面生命周期的变动状况,防止开发过程中踩坑。

🌟官网文档:https://developer.android.goo…

🌟navigation 我的项目地址:https://github.com/googlecode…

💡本文 Demo 地址:https://github.com/taxze6/Jet…

应用 Navigation 具备什么劣势?

  • 解决 Fragment 事务
  • 默认状况下,能正确处理往返操作
  • 为动画和转换提供标准化资源
  • 实现和解决深层链接
  • 包含导航界面模式,例如抽屉式导航栏和底部导航,咱们只须要实现大量的代码编写
  • Safe Args – 可在指标之间导航和传递数据时提供类型平安的 Gradle 插件
  • ViewModel 反对 – 您能够将 ViewModel 的范畴限定为导航图,以在图标的指标之间共享与界面相干的数据

如何应用 Navigation 呢?

Navigation 目前仅 AndroidStudio 3.2 以上版本反对,如果您的版本有余 3.2,请点此下载最新版 AndroidStudio(2202 年了应该没有人还在用 3.2 以下的版本吧!🐤)

在开始学习 Navigation 组件之前,咱们须要先对 Navigation 次要组成部分有个简略的理解,Navigation 由三局部组成:

  • Navigation graph:一个蕴含所有导航相干信息的 XML 资源
  • NavHostFragment:一种非凡的Fragment,用于承载导航内容的容器
  • NavController:治理利用导航的对象,实现 Fragment 之间的跳转等操作

上面咱们正式开始学习 Navigation 啦

第一步:增加依赖

//project 的 Navigation 依赖设置
dependencies {
  // 文章公布时的最新稳固版本:def nav_version = "2.4.2"
​
  // 应用 java 作为开发语言增加上面两行:implementation "androidx.navigation:navigation-fragment:$nav_version"
  implementation "androidx.navigation:navigation-ui:$nav_version"
​
  // Kotlin:implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
  implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
​
//Compose 版本:implementation "androidx.navigation:navigation-compose:$nav_version"

第二步:创立导航图

右键点击 res 目录,而后顺次抉择 NewAndroid Resource Directory。此时零碎会显示 New Resource Directory 对话框。Directory name输出你的文件夹名(个别为 navigation),Resource type 抉择navigation

右键 navigation 文件夹,而后 newNavigation Resource FileFile name中输出名称(罕用nav_graph_main 或 nav_graph

第三步:创立 Fragment

为了让跳转更加的丰盛,咱们这里创立三个Fragment

咱们能够本人手动创立:

FirstFragment:

<?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=".FirstFragment">
​
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="hello world" />
</FrameLayout>
class FirstFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {return inflater.inflate(R.layout.fragment_first, container, false)
    }
}

另外创立两个和 FirstFragement 一样的:SecondFragmentThirdFragment

咱们也能够通过 Navigation graph 创立

咱们在新建好的 nav_graph_main.xml 下,在右上角切换到 Design 模式,而后在 Navigation Editor 中,点击 Create new destination,抉择所须要的Fragment 后,点击 Finish,你就会发现Fragment 曾经呈现在咱们能够拖动的面板中了。

第四步:将 Fragment 拖入面板并进行跳转配置

只须要在 Navigation Editor 中双击想要的 Fragment 就会被退出到面板中啦。

点击其中一个Fragment,你会发现,在他的左边会有一个小圆点,拖曳小圆点指向想要跳转的那个Fragment,咱们这里设置FirstFragmentSecondFragmentThirdFragmentFirstFragment


咱们将 nav_graph_main.xml 切换到 Code 下,咱们来解读一下xml

<?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_main"
    app:startDestination="@id/firstFragment">
    <fragment
        android:id="@+id/firstFragment"
        android:name="com.taxze.jetpack.navigation.FirstFragment"
        android:label="fragment_first"
        tools:layout="@layout/fragment_first" >
        <action
            android:id="@+id/action_firstFragment_to_secondFragment2"
            app:destination="@id/secondFragment" />
    </fragment>
    <fragment
        android:id="@+id/secondFragment"
        android:name="com.taxze.jetpack.navigation.SecondFragment"
        android:label="fragment_second"
        tools:layout="@layout/fragment_second" >
        <action
            android:id="@+id/action_secondFragment_to_thirdFragment2"
            app:destination="@id/thirdFragment" />
    </fragment>
    <fragment
        android:id="@+id/thirdFragment"
        android:name="com.taxze.jetpack.navigation.ThirdFragment"
        android:label="fragment_third"
        tools:layout="@layout/fragment_third" >
        <action
            android:id="@+id/action_thirdFragment_to_firstFragment"
            app:destination="@id/firstFragment" />
    </fragment>
</navigation>
  • navigation是根标签,通过 startDestination 配置默认启动的第一个页面,这里配置的是firstFragment,咱们能够在代码中手动改mainFragment(启动时的第一个 Fragment),也能够在可视化面板中点击Fragment,再点击Assign Start Destination,同样能够批改mainFragment

  • fragment标签就代表这是一个 Fragment
  • action标签定义了页面跳转的行为,就是上图中的每条线,destination定义跳转的指标页,还能够退出跳转时的动画

💡留神:在 fragment 标签下的 android:name 属性,其中的包名的是否正确申明

第五步:解决 MainActivity

编辑 MainActivity 的布局文件,在布局文件中增加 NavHostFragment。咱们须要通知NavigationActivity,咱们的 Fragment 展现在哪里,所以 NavHostFragment 其实就是导航界面的容器

<?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/nav_host_fragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph_main" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • fragment标签下的 android:name 是用于指定NavHostFragment
  • app:navGraph是用于指定导航视图的
  • app:defaultNavHost=true是在每一次 Fragment 切换时,将点击记录在堆栈中保存起来,在须要退出时,按下返回键后,会从堆栈拿到上一次的 Fragment 进行显示。然而在某些状况下,这样的操作不是很敌对,不过好在咱们只须要将 app:defaultNavHost=true 改为 app:defaultNavHost=false 或者删除这行即可。在其为 false 的状况下,无论怎么切换Fragment,再点击返回键就都间接退出app。当然咱们也能够对其堆栈进行监听,从而来实现,点击一次返回键回到主页,再点击一次返回键退出app

批改MainActivity

咱们重写了 onSupportNavigateUp,示意咱们将Activityback点击事件委托进来

class MainActivity : AppCompatActivity() {override  fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
​
    override fun onSupportNavigateUp(): Boolean {return findNavController(R.id.nav_host_fragment).navigateUp()}
}

第六步:解决 Fragment 的对应跳转事件

Fragment布局:给一个按钮用于跳转,一个 TextView 用于标识,三个 Fragment 布局雷同

<?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=".FirstFragment">
​
    <Button
        android:id="@+id/firstButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="点击跳转到第二个 fragment" />
​
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@string/hello_first_fragment" />
​
</FrameLayout>
​
//secondFragment 中退出:
<Button
        android:id="@+id/firstButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="点击跳转到第三个 fragment" />
​
//thirdFragment 中退出:<Button
        android:id="@+id/firstButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="返回第一个 fragment" />

②配置 Fragment 对应的跳转事件

class FirstFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {return inflater.inflate(R.layout.fragment_first, container, false)
    }
   
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.firstButton).apply {
         setOnClickListener {it.findNavController().navigate(R.id.action_firstFragment_to_secondFragment2)
         }
        }
    }
}
​
//secondFragment 中退出:override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.firstButton).apply {
         setOnClickListener {it.findNavController().navigate(R.id.action_secondFragment_to_thirdFragment2)
         }
        }
}
​
//thirdFragment 中退出:override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.firstButton).apply {
            setOnClickListener {it.findNavController().navigate(R.id.action_thirdFragment_to_firstFragment)
            }
        }
}

其中的 R.id.action_firstFragment_to_secondFragment2 这样的标识,是在 nav_graph_main.xmlaction标签下配置的。

<action
    android:id="@+id/action_firstFragment_to_secondFragment2"
    app:destination="@id/secondFragment" />

③最初的效果图:

跳转动画 & 自定义动画

咱们会发现,刚刚的例子中,咱们在跳转界面时,没有左滑右滑进入界面的动画,显得很僵硬,所以咱们要给跳转过程中增加上动画。

增加默认动画:

nav_graph_main.xml 文件中的 Design 模式下,点击连贯两个 Fragment 的线。而后你会发现在右侧会呈现一个 Animations 的面板,而后咱们点击 enterAnim 这些选项最右侧的椭圆点,而后就会弹出 Pick a Resoure 的面板,咱们能够在这里抉择须要的动画,这里咱们就设置 nav_default_enter_anim。同理exitAnim 咱们也设置一个动画,nav_default_exit_anim。而后运行代码你就发现一个突变的跳转动画。而后配置动画后会发现 action 多了动画相干的属性

<fragment
    android:id="@+id/firstFragment"
    android:name="com.taxze.jetpack.navigation.FirstFragment"
    android:label="fragment_first"
    tools:layout="@layout/fragment_first" >
    <action
        android:id="@+id/action_firstFragment_to_secondFragment2"
        app:destination="@id/secondFragment"
        app:enterAnim="@anim/nav_default_enter_anim"
        app:exitAnim="@anim/nav_default_exit_anim"
        />
</fragment>

  • enterAnim: 跳转时的指标页面动画
  • exitAnim: 跳转时的原页面动画
  • popEnterAnim: 回退时的指标页面动画
  • popExitAnim: 回退时的原页面动画

自定义动画

💡 在真正的业务需要中是会有很多不同的跳转动画的,官网提供的默认动画是不够的,所以咱们要学会自定义动画。

⑴创立 Animation 资源文件

右键点击 res 目录,而后顺次抉择 NewAndroid Resource File。此时零碎会显示 New Resource File 对话框。File name输出你的文件夹名(这里设置为 slide_from_left),Resource type 抉择 Animation,而后咱们就能够发下在res 目录下多了一个 anim 目录,外面寄存着咱们自定义的动画。

⑵编写咱们的动画代码

这里举几个罕用的例子:

// 左滑成果
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="300"
        android:fromXDelta="-100%"
        android:toXDelta="0%">
    </translate>
</set>
// 右滑成果
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="300"
        android:fromXDelta="0%"
        android:toXDelta="100%">
    </translate>
</set>
// 旋转成果
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:duration="1000"
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />
​
    <rotate
        android:duration="1000"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" />
</set>

罕用的属性:

属性 介绍
alpha 透明度设置成果
scale 大小缩放成果
rotate 旋转成果
translate 位移成果

罕用设置:

属性 介绍
android:duration 动画时长
fromXX 开始状态
toXX 完结状态

⑶应用自定义动画文件

应用自定义动画也是和应用默认动画是一样的。

旋转成果:

如何传递数据?

💡Navigation 反对您通过定义目的地参数将数据附加到导航操作。个别状况下,倡议传递大量数据。例如传递 userId,而不是具体用户的信息。如果须要传递大量的数据,还是举荐应用 ViewModel。

nav_graph_main.xml 文件中的 Design 模式下。点击选中其中的 Fragment。在右侧的Attributes 面板中,点击Arguments 选项右侧的加号。增加须要的参数。增加参数后,在箭头 Action 上点击,会在左边的 Argument Default Values中显示这个 userId 变量,在 xml 中也能够看到

// 伪代码,请勿间接 cv
<fragment
   ... 
   >
   ...
    <argument
        android:name="userId"
        android:defaultValue="1"
        app:argType="integer" />
</fragment>

代码解决:

// 默认将 箭头 Action 中设置的参数传递过来
it.findNavController().navigate(R.id.action_firstFragment_to_secondFragment2)

动静传递数据

①咱们能够应用 Bundle 在目的地之间传递参数

// 伪代码,请勿间接 cv
view.findViewById<Button>(R.id.firstButton).setOnClickListener {val bundle = Bundle()
    bundle.putString("userId", "1")
    val navController = it.findNavController()
    navController.navigate(R.id.action_firstFragment_to_secondFragment2, bundle)
}

②而后咱们就能够承受参数啦

在对应的 Fragment:

val tv = view.findViewById<TextView>(R.id.textView)
tv.text = arguments?.getString("userId")

在 Activity 应用 setGraph 切换不同的 Navigation

通常状况下,咱们不止一个 navigation 的文件,咱们须要依据业务状况去判断应用哪个,这里就能够用到咱们的 setGraph 去切换不同的 Navigation 了。

①把 activity_mainfragment标签下的 app:navGraph 这个属性去除

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

②在代码中通过 setGraph 设置app:navGraph

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initNav(1)
    }
    private fun initNav(id: Int) {var controller = Navigation.findNavController(this@MainActivity, R.id.nav_host_fragment)
        if (id == 1) {
            // 设置对应的 app:navGraph
            controller.setGraph(R.navigation.first)
        }
        if (id == 2) {controller.setGraph(R.navigation.second)
        }
        this@MainActivity.finish()}
}

到此,咱们曾经讲完了 Navigation 大部分的应用状况,上面来解说几个重要的点,并通过一个案例来学习总结这篇文章吧。

NavController

💡 咱们在后面曾经讲了 Navigation 的应用,在解决 Fragment 的对应跳转事件时,咱们用到了 findNavController 这个办法,其实呢,这个就是 Navigation 的三局部中的 NavController 中的一个 api。那么什么是NavController 呢?它是负责操作 Navigation 框架下的 Fragment 的跳转与退出、动画、监听以后 Fragment 信息,当然这些是基本操作。因为除了在 Fragment 中调用,在理论状况中它也能够在 Activity 中调用。如果能灵便的应用它,它能够帮你实现任何模式的页面跳转,也能够应用 TabLayout 配合 Navigation 在主页进行分页设计。

如何获取 NavController 实例呢?

在后面的根底应用中咱们也用到了。

// 伪代码,请勿间接 cv
//activity:
//Activity.findNavController(viewId: Int)
findNavController(R.id.nav_host_fragment).navigateUp()
​
//Fragment:
//Fragment.findNavController()
//View.findNavController()
findNavController().navigate(R.id.action_thirdFragment_to_firstFragment)

Navigation 罕用操作:

①popBackStack 弹出 Fragment

当初咱们从 oneFragment 跳转到 secondFragment 在到 thirdFragment,而后咱们想从thirdFragment 回到 secondFragment 那儿就能够应用popBackStack

override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        .....
        btn.setOnClickListener{
            // 弹出 Fragment
            controller.popBackStack()}
}

②弹出到指定的 Fragment

也是应用 popBackStack,这个办法能够 实现清空两头导航栈堆的需要

//xxxFragment 弹出到指定的 Fragment。// 第二个参数的布尔值如果为 true 则示意咱们参数一的 Fragment 一起弹出, 意思就是如果是 false 就 popBackStack 到
//xxxFragment,如果是 true,就在 xxxFragment 在 popBackStack()一次
controller.popBackStack(xxxFragment,true)

③navigateUp() 向上导航

findNavController(R.id.nav_host_fragment).navigateUp()

navigateUp也是执行返回上一级 Fragment 的性能。和 popBackStack 性能一样。那么既然它存在必定是有它非凡的中央的。navigateUp向上返回的性能其实也是调用 popBackStack 的。然而,navigateUp的源码里多了一层判断,判断这个 Navigation 是否是最初一个 Fragment。应用popBackStack() 如果以后的返回栈是空的就会报错,因为栈是空的了,navigateUp()则不会,还是停留在以后界面。

④增加导航监听

val listener: NavController.OnDestinationChangedListener =
                object : OnDestinationChangedListener() {
                    fun onDestinationChanged(
                        controller: NavController,
                        destination: NavDestination,
                        @Nullable arguments: Bundle?
                    ) {Log.d(TAG, "onDestinationChanged: id = ${destination.getId()}")
                  }
          }
// 增加监听
controller.addOnDestinationChangedListener(listener)
// 移除监听
controller.removeOnDestinationChangedListener(listener)

⑤获取以后导航目的地

应用 getCurrentDestination 能够获取以后导航的目的地

// 获取
val destination = controller.getCurrentDestination()
Log.d(TAG, "onCreate: NavigatorName = ${destination.getNavigatorName()}")
Log.d(TAG, "onCreate: id = ${destination.getId()}")
Log.d(TAG, "onCreate: Parent = ${destination.getParent()}")

⑥判断以后页面显示的 Fragment 是不是指标 Fragment

// 可间接 cv
fun <F : Fragment> isActiveFragment(fragmentClass: Class<F>): Boolean {val navHostFragment = this.supportFragmentManager.fragments.first() as NavHostFragment
    navHostFragment.childFragmentManager.fragments.forEach {if (fragmentClass.isAssignableFrom(it.javaClass)) {return true}
    }
    return false
}

应用 Safe Args 确保类型平安

💡 通过下面的 NavController 咱们就能够实现 fragment 之间的跳转,然而 Google 倡议应用 Safe Args Gradle 插件实现。这个插件能够生成简略的对象和构建器类,这些类就能够在目的地之间进行平安的导航和参数的传递啦。

那么,该如何应用 Safe Args呢。

①在我的项目最里面的 build.gradle 中退出

// 将其放在 plugins{}之前
buildscript {
    repositories {google()
    }
    dependencies {
        def nav_version = "2.4.2"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

②在 appmodule 下的 build.gradle 退出

如需生成实用于 Java 模块或 JavaKotlin 混合模块的 Java 语言代码

apply plugin: "androidx.navigation.safeargs"

如需生成实用于 Kotlin独有的模块的 Kotlin 代码,请增加以下行:

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

💡 要应用 Safe Args,必须在 gradle.properties 这个文件中退出

android.useAndroidX=true
android.enableJetifier=true

为了防止生成的类名和办法名过于简单,须要对导航图进行调整,批改了 action 的 id,因为主动生成的 id 太长了,会导致插件生成的类名和办法名也很长。

// 伪代码,请勿间接 cv
<fragment
    android:id="@+id/blankFragment"
    android:name="com.taxze.jetpack.navigation.BlankFragment"
    android:label="fragment_blank"
    tools:layout="@layout/fragment_blank" >
    <action
        android:id="@+id/toSecond"
            批改此处 id
        app:destination="@id/blankFragment2" />
</fragment>

而后就会为咱们生成 BlankFragmentBlankFragment2的类啦,而后就能够和下面一样应用,传递参数啦。

var action = BlankFragment.actionJump("111")

也能够应用 set 办法 对对应的参数进行赋值

action.setParam("222")

通过 Navigation 模拟 WeChat 底部跳转

💡通过 Navigation 实现开发中超级罕用的底部跳转性能

话不多说,先上效果图:

①右键点击 res 目录,而后顺次抉择 NewAndroid Resource File。此时零碎会显示 New Resource File 对话框。File name输出你的文件夹名(这里设置为 menu),Resource type 抉择 Menu,而后咱们就能够发下在res 目录下多了一个 menu 目录,外面寄存着咱们底部跳转的item

②进入 menu.xmlDesign

填入四个Item,并别离设置idtitleicon


③创立四个 Fragment,并在Navigation 中建设链接

Fragment 的布局非常简略,这里就放一个的代码。

<?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=".HomeFragment">
​
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="Home" />
</FrameLayout>
class HomeFragment : Fragment() {
​
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {return inflater.inflate(R.layout.fragment_home, container, false)
    }
​
}

nav_graph_main.xml 建设连贯,留神这里每个 Fragmentid要和 menu.xml 中的 id 一一对应


④在 activity_main 中应用 BottomNavigationView 建设底部跳转

这里在 drawable 下创立一个 selector_menu_text_color.xml 用于辨别以后的Item

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#818181" android:state_checked="false"/>
    <item android:color="#45C01A" android:state_checked="true"/>
</selector>
<?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/nav_host_fragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph_main" />
​
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:itemIconTint="@drawable/selector_menu_text_color"
        app:labelVisibilityMode="labeled"
        app:itemTextColor="@drawable/selector_menu_text_color"
        app:menu="@menu/menu" />
</androidx.constraintlayout.widget.ConstraintLayout>

⑤在 MainActivty 中设置切换逻辑

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
        // 去除标题栏
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
        setContentView(R.layout.activity_main)
​
        val navController: NavController = Navigation.findNavController(this, R.id.nav_host_fragment)
        val navigationView = findViewById<BottomNavigationView>(R.id.nav_view)
        NavigationUI.setupWithNavController(navigationView, navController)
    }
}

这样咱们就能够实现效果图中的成果啦,具体代码能够查看 Git 仓库😉

尾述

这篇文章曾经很具体的讲了 Jetpack Navigation 的大部分用法,不过在看完文章后,你仍需多多实际,置信你很快就能够把握 Navigation 啦😺 因为我自己能力也无限,文章有不对的中央欢送指出,有问题欢送在评论区留言探讨~

对于我

Hello,我是 Taxze,如果您感觉文章对您有价值,心愿您能给我的文章点个❤️,也欢送关注我的博客。

如果您感觉文章还差了那么点货色,也请通过 关注 督促我写出更好的文章——万一哪天我提高了呢?😝

根底系列:

2022 · 让我带你 Jetpack 架构组件从入门到精通 — Lifecycle

学会应用 LiveData 和 ViewModel,我置信会让你在写业务时变得轻松🌞

当你真的学会 DataBinding 后,你会发现“这玩意真香”!

Navigation — 这么好用的跳转治理框架你确定不来看看?(本文🌟)

以下局部还在码字,连忙点个珍藏吧🔥

2022 · 让我带你 Jetpack 架构组件从入门到精通 — Room

2022 · 让我带你 Jetpack 架构组件从入门到精通 — Paging3

2022 · 让我带你 Jetpack 架构组件从入门到精通 — WorkManager

2022 · 让我带你 Jetpack 架构组件从入门到精通 — ViewPager2

2022 · 让我带你 Jetpack 架构组件从入门到精通 — 登录注册页面实战(MVVM)

进阶系列:

协程 + Retrofit 网络申请状态封装

Room 缓存封装

…..

退出移动版