Android实现底部导航栏方法(Navigation篇)

这篇具有很好参考价值的文章主要介绍了Android实现底部导航栏方法(Navigation篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

底部导航栏一直是大部分App不可缺失的一部分
最近注意到Jetpack中的Navigation支持Fragment的切换操作
特此浅研究一下

导入和基本使用

选择性跳过

导入

此处使用Google开发者文档中介绍

dependencies {
  def nav_version = "2.5.3"

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

  // 多模块使用
  implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

  // 测试使用
  androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"

  // Jetpack Compose使用
  implementation "androidx.navigation:navigation-compose:$nav_version"
}

基础使用

使用nav文件配合 FragmentContainerView组件 实现Fragment的切换操作

创建nav文件

导入后,在项目的res文件夹下,右键选择Android Resource File,弹出弹窗Android实现底部导航栏方法(Navigation篇)Resource type下拉选择Navigation即可,剩下的就是填写文件名
完成后会在res文件下创建一个navigation文件夹 ,里面就存放着nav文件

编辑Nav文件

打开Nav文件,可以看到顶部有一排按钮
Android实现底部导航栏方法(Navigation篇)

分别是

  • 添加页面 (Fragment、Activiry、include)
  • 创建分组 (选择一个或多个页面进行分组)
  • 设置初始页 (选择一个页面,设置为初始页,即默认页,设置为默认页的页面左上角会出现一个房子图标)
  • 创建depplink (选择一个页面创建深层链接)
  • 添加 action (选择一个页面 添加跳转动作)
  • 整理布局 (全部页面重排,优化布局)

首先使用添加页面 添加三个已经写好的Fragment
当然使用写代码的方式也是可以的

添加页面(代码版)
<?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"
    app:startDestination="默认页id">

	<!--例-->
    <fragment
        android:id="@+id/标识此fragment的id"
        android:name="fragment类文件路径"
        android:label="fragment名称"
        tools:layout="fragment对应的layout" />

</navigation>
添加页面(图解版)

Android实现底部导航栏方法(Navigation篇)
可以通过搜索框搜索,点击需要添加的页面即可
此时在代码处会生成一个fragment标签

Android实现底部导航栏方法(Navigation篇)
如图所示 成功添加了一个页面
如果需要添加页面预览 则在fragment处添加标签 layout 值为 fragment对应的layout
Android实现底部导航栏方法(Navigation篇)

创建导航动作 action

action是跳转到fragment的关键要素

创建action(代码版)

最基本的写法

<action
        android:id="@+id/标识此action的id"
        app:destination="@id/目的地的fragment Id" />
创建action(图解版)

Android实现底部导航栏方法(Navigation篇)点击起始的fragment,右边有一个可以拖动的箭头,将箭头拖至目的地fragment即可
上述操作完成后会在 testFragment 中生成一段action标签
当然action的内容不止这些

编辑action参数

通过查看NavAction的源码参数 可以看到action有数个标签可以定义
(按住Ctrl+鼠标点击action中的destination属性即可)

 <declare-styleable name="NavAction">
        <attr name="android:id"/>
        <!-- destination  目的地的id  -->
        <attr format="reference" name="destination"/>
        <attr format="boolean" name="launchSingleTop"/>
        <attr format="boolean" name="restoreState"/>
        <attr format="reference" name="popUpTo"/>
        <attr format="boolean" name="popUpToInclusive"/>
        <attr format="boolean" name="popUpToSaveState"/>
        <attr format="reference" name="enterAnim"/>
        <attr format="reference" name="exitAnim"/>
        <attr format="reference" name="popEnterAnim"/>
        <attr format="reference" name="popExitAnim"/>
    </declare-styleable>

同时可以通过右侧Attributes 页进行参数查看

launchSingleTop

默认false,类似Activity的singleTop
设为true后 activity的singleTop会判断顶部的activity是否为当前activity,是则复用,否则新建
navigation的singleTop会判断顶部的fragment是的为目的地fragment ,是则销毁顶部,重新创建放置在顶部
可见图 唯一的区别就是 执行了action动作后有无删除旧fragment
Android实现底部导航栏方法(Navigation篇)
此处使用了以下action

 <action
        android:id="@+id/action_testFragment_self_singleTop"
        app:launchSingleTop="true"
        app:destination="@id/testFragment" />
 <action
        android:id="@+id/action_testFragment_self"
        app:destination="@id/testFragment" />
popUpTo

默认为空
设为某个fragment的id后 执行此action 会挨个出栈 直到出栈的fragment为popUpTo指定的fragment (此fragment不出)然后再创建 目的地fragment
以下为图解Android实现底部导航栏方法(Navigation篇)主要看右下角处 2->1 popUpTo = 1
当popUpTo指定1后 会把所有不是 1 的fragment出栈,再在旧的1上面入栈新的1
如下图,即使多个1存在,只会弹出最上层的1之上的fragment
Android实现底部导航栏方法(Navigation篇)

popUpToInclusive

默认false
结合popUpTo使用,当popUpToInclusive为true的时候,会把旧的1也出栈
如下图,区别与上图 本次连黄色的1都出栈了
Android实现底部导航栏方法(Navigation篇)

popUpToSaveState

默认false
结合popUpTo使用
设为true后 popUpTo操作弹出的fragment 都会保存状态
以便restoreState 恢复操作

restoreState

默认false
结合popUpToSaveState使用
设为true后 还原目的地fragment的状态
如果之前没有保存状态 此参数不起效
Android实现底部导航栏方法(Navigation篇)
如图 当popUpToSaveState为true后 弹出的fragment会保存到一个Map内
之后再调用action
action中restoreState为true
action的目的地为2
此时就会取出map中ID为2的fragment 重新放进栈中
取出顺序为 先popup的后入栈 也就先显示 顺序和popup前一样
需要注意的是 这样子的状态保存实际上需要view model配合使用 ,当fragment销毁(onDestroy)后,fragment绑定的viewmodel没有跟着销毁
此时恢复状态,fragment依旧会onCreate,就需要从view model中获取数据,所以数据需要保存在viewmodel才是最优选

  • 当 popUpTo和起始idfragment不同时,会发生不同情况
  • popUpToInclusive 会影响状态恢复
    Android实现底部导航栏方法(Navigation篇)
    如图,当fragment3跳转至fragment4时 弹出2以上的所有fragment,此时两个fragment3都会保存状态,直到fragment4跳至fragment2,并使用restoreState=true属性后,会把两个fragment3恢复,这时就与之前冲突了。
    这时再把popUpToInclusive改为true,就会发生以下情况
    Android实现底部导航栏方法(Navigation篇)
    可以看到,把popUpToInclusive设为true后,弹出了fragment2以上所有页面,包括fragment2自己,在随后的恢复中,原先的fragment3被置顶,明明是4->2却显示3!
    原因未知,如果上面描述有错误,或者有更好的见解,欢迎评论区讨论。

使用nav文件

这里需要使用官方的组件进行fragment的显示,具体步骤如下 在activity的layout中添加

   <androidx.fragment.app.FragmentContainerView
        android:id="@+id/main_fragment_container"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav文件名" />

这里有两个属性需要说明

app:defaultNavHost:设为false时,返回就退出Activity 设为true时,返回就是fragment出栈
app:navGraph:设置nav文件

跳转Fragment

引用官方文档中的话

使用 FragmentContainerView 创建 NavHostFragment,或通过 FragmentTransaction 手动将 NavHostFragment 添加到您的 Activity 时,尝试通过 Navigation.findNavController(Activity, @IdRes int) 检索 Activity 的 onCreate() 中的 NavController 将失败。您应改为直接从 NavHostFragment 检索 NavController。

简单来说就是,先尝试下列方法获取控制器
Kotlin:

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

Java:

NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)

如果报错,获取不了,应该改为

   val navHostFragment =
            supportFragmentManager.findFragmentById(R.id.main_fragment_container) as
                    NavHostFragment
  val controller = navHostFragment.navController
      NavHostFragment f = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.main_fragment_container);
        NavController controller;
        if (f != null) {
            controller = f.getNavController();
        }

Activity所继承的必须为 AppCompatActivity
拿到控制器后,只需要

 controller.navigate( action的ID )

即可完成页面跳转,例:

    <fragment
        android:id="@+id/testFragment"
        android:name="com.a.demo.ui.nav.TestFragment"
        android:label="TestFragment"
        tools:layout="@layout/fragment_test">
        <action
            android:id="@+id/action_testFragment_to_test2Fragment"
            app:destination="@id/test2Fragment" />
    </fragment>
    <fragment
        android:id="@+id/test2Fragment"
        android:name="com.a.demo.ui.nav.Test2Fragment"
        android:label="Test2Fragment"
        tools:layout="@layout/fragment_test2">
    </fragment>
controller.navigate(R.id.action_testFragment_to_test2Fragment)

这样就完成了从testFragment跳转至test2Fragment的操作

底部导航栏实现方法

假如现在底部导航栏有五个按钮和五个fragment

创建nav文件

	<fragment
        android:id="@+id/mainFragment1"
        android:name="com.a.demo.ui.activity.main.MainFragment1"
        android:label="MainFragment1"
        tools:layout="@layout/fragment_1" />
    <fragment
        android:id="@+id/mainFragment2"
        android:name="com.a.demo.ui.activity.main.MainFragment2"
        android:label="MainFragment2" />
    <fragment
        android:id="@+id/mainFragment3"
        android:name="com.a.demo.ui.activity.main.MainFragment3"
        android:label="MainFragment3" />
    <fragment
        android:id="@+id/mainFragment4"
        android:name="com.a.demo.ui.activity.main.MainFragment4"
        android:label="MainFragment4" />
    <fragment
        android:id="@+id/mainFragment5"
        android:name="com.a.demo.ui.activity.main.MainFragment5"
        android:label="MainFragment5" />

点击导航

在activity处,设置五个点击事件 分别对应五个按钮(此处不展示详细代码)

//获取控制器
 		val navHostFragment = supportFragmentManager.findFragmentById(R.id.main_fragment_container) as NavHostFragment
        val controller = navHostFragment.navController
		//设置导航配置
        val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true)
        builder.setPopUpTo(
            controller.graph.findStartDestination().id,
            inclusive = false,
            saveState = true
        )
        //设置点击事件
        vb.but1.setOnClickListener {
			controller.navigate(R.id.mainFragment1,null,builder.build())
        }
        vb.but2.setOnClickListener {
           controller.navigate(R.id.mainFragment2,null,builder.build())
        }
        vb.but3.setOnClickListener {
           controller.navigate(R.id.mainFragment3,null,builder.build())
        }
        vb.but4.setOnClickListener {
          controller.navigate(R.id.mainFragment4,null,builder.build())
        }
        vb.but5.setOnClickListener {
           controller.navigate(R.id.mainFragment5,null,builder.build())
        }

解释一下上面代码

navigate方法可以传fragment的id直接跳转,而不使用action ID,这时等同于 当前fragment->传递的fragment Android实现底部导航栏方法(Navigation篇)
NavOptions.Builder是导航配置,等同于action中其他参数 ,但有更高的自定义程度,相当于动态控制
controller.graph.findStartDestination().id 可以拿到当前当前fragment ID

此时的activity的布局需要修改

app:defaultNavHost=“false”

这种导航栏方式,fragment1始终被压在栈底,如果将返回键交予fragment分发,就会出现先退到fragment1再退出activity的情况

  <androidx.fragment.app.FragmentContainerView
        android:id="@+id/main_fragment_container"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="false"
        app:navGraph="@navigation/nav_main" />

结语

到此,Nav自定义导航栏已经实现,基本使用的模块来源日常使用经验。
至于底部导航栏,网上大部分人都推荐使用 BottomNavigationView 配合使用

  <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/main_bottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_50"
        app:menu="@menu/menu_main" />

好用,但自定义样式比较难,然后就只能翻BottomNavigationView的源码,看它是怎么实现切换页面而不销毁fragment
Android实现底部导航栏方法(Navigation篇)文章来源地址https://www.toymoban.com/news/detail-459294.html

到了这里,关于Android实现底部导航栏方法(Navigation篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • android : 底部导航栏的实现(使用ViewPager和BottomNavigationView)

      本案例中需要用的控件ViewPager和BottomNavigationView ViewPager:主要是页面的切换 Fragment:碎片(也就是每个页面的内容) BottomNavigationView:底部导航栏 非常简单,主要就是一个Viewpager和BottomNavigationView 先来说一下思路:BottomNavigationView底部导航栏   ViewPager+Fragment页面        

    2024年02月03日
    浏览(41)
  • android 关于TabLayout联动ViewPager2 实现底部导航栏

    最近在心血来潮想写在app 不过我关于android可以说是0基础 在写底部导航栏的时候去问了大佬才知道TabLayout和ViewPager 花了两天才看懂... 这里只是简单介绍因为我不准备专门做安卓软件所以在学的途中很多地方没有认真记 本篇文章使用的代码是Java 这里官方是有将两个进行联动

    2024年01月25日
    浏览(43)
  • 【Android入门到项目实战-- 11.2】—— 实现底部导航栏(RadioGroup+Fragment)

            效果如下,使用RadioGroup实现,不能左右滑动切换页面,适用于导航页里还有需要切换页面的场景,如果需要滑动效果,使用ViewPager实现。         以下示例按照图上实现,具体多少个页面,按需修改。         由于需要用到icon,提前下载好图标到drawable文件

    2024年02月10日
    浏览(78)
  • Android Navigation 导航切换fragment用法

    对于Android Navigation组件的导航到Fragment,您可以按照以下步骤操作: 首先,在您的项目的build.gradle文件中添加Navigation依赖: 在你的res目录下的navigation文件夹中创建一个nav_graph.xml文件,并定义您的导航图。 在您的布局文件中,添加NavHostFragment作为导航的目标。 在您的Activi

    2024年02月12日
    浏览(42)
  • Android studio中使用ViewPager和BottomNavigationView实现底部导航栏和碎片的同步切换

    通过几次的踩雷和摸索,完成了以上的操作,本教程写的详细全面,包教包会,对新手有好,看了不会的联系我,我倒立洗头给你看。 所需控件: fragment 作为Android中最常用的控件,它有自己的声明周期,可以粗略地等比为能够分屏的activity,但是和activity有区别,fragment有自

    2024年02月08日
    浏览(48)
  • android中实现底部导航栏

            底部导航栏在app应用中是十分常见了,大部分的安卓应用中也都实现了底部导航栏的功能,这里我就以我以前做的一个简单小说阅读软件为例,为大家演示一下底部导航栏的使用,需要的朋友直接复制代码过去改写就行了。         这里包含了一些进行操作实际

    2024年02月19日
    浏览(46)
  • Android底部导航栏之BottomNavigationView

    1,首先需要添加依赖: implementation \\\'com.google.android.material:material:1.1.0\\\' 2,布局文件中引入: 3,常用属性: app:itemTextColor 文字的颜色,可以通过 selector 来控制选中和未选中的颜色 app:itemIconTint 图标的颜色,可以通过 selector 来控制选中和未选中的颜色 app:itemIconSize 图标大小,

    2024年02月08日
    浏览(74)
  • Android BottomNavigation底部导航栏使用

    原文地址: Android BottomNavigation底部导航栏使用 - Stars-One的杂货小窝 本文侧重点记录一些特殊的样式设置,所以基本使用这里就简单概述一下,详细图文可以去找其他人的博文 1.创建对应的menu菜单文件 2.xml布局引用menu菜单 3.启动Activity预览效果 可以使用 setOnItemSelectedListener 方法监

    2024年02月12日
    浏览(52)
  • Flutter写一个android底部导航栏框架

    废话不多说,上代码: 在上述示例中,我们创建了一个 MyHomePage 小部件,它是 StatefulWidget 。 MyHomePage 包含底部导航栏和相关页面内容。通过 BottomNavigationBar 和 currentIndex 属性,我们可以控制当前选中的导航项并在 onTap 回调中更新状态。 在 items 属性中,我们设置了三个 Bott

    2024年02月14日
    浏览(37)
  • 【Android】底部导航栏【BottomNavigationView】+【ViewPage2】

    问题需求 实现底部导航栏切换 问题解决 最简单的实现方式就是使用系统自动生成的模板页面,但是有时候会有一些问题,特别是需要去除【ActionBar】的情况下,这种情况下使用系统的模板页面就不好用了,此时可以使用下面这种解决方式。 【BottomNavigationView】+【ViewPage2】

    2023年04月18日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包