Android 底部导航栏+页面切换

本文介绍了在Android应用中实现底部导航栏与页面切换的两种方案,包括使用NavigationUI和ViewPager2。通过NavigationUI,可以方便地设置底部栏并链接导航图,但可能导致Fragment每次切换都重建。使用ViewPager2结合FragmentStateAdapter可以缓存页面,保持页面状态。此外,还解决了在item2页面点击返回键时正确退出的问题。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

lzyprime 博客 (github)
更新时间: 2020.12.21
创建时间:2020.11.25
qq及邮箱:2383518170

kotlin & android 笔记


更新

2020.12.21 解决 “在item2页面点击返回键会返回item1, 而非退出” 问题

之前笔记里(android navigation组件)记录整个导航组件时, 其中关于自定义返回导航只是简单一提, 并用于在MainActivity的回调里整体组织路由。

提供自定义返回导航 官网文档

Item2, Item3页面注册返回事件, addCallBack(LifecycleOwner, OnBackPressedCallback)版本, 会检测生存期,在页面被销毁时自动删掉回调。OnBackPressedCallback 构造函数传入 Boolean 表示回调初始是否开启(isEnable), 之后可以调用它的 setEnable 来改变状态。

// 仓库已经更新
class Item2Fragment: Fragment(R.layout.item2_fragment){
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requireActivity().onBackPressedDispatcher.addCallback(this, object :OnBackPressedCallback(true){
            override fun handleOnBackPressed() {
                requireActivity().finish()
            }
        })
    }
}

原文:

λ:

# android bottom navigation demo
# 仓库地址: https://github.com/lzyprime/android_demos
# branch: bottom_navigation

git clone -b bottom_navigation https://github.com/lzyprime/android_demos

底部导航配合多页面切换是常见逻辑,微信,qq,抖音,淘宝等等,常见app里几乎都有这种设计。

底部导航栏涉及到图标和标题在点击时的变化(颜色,大小,选中与未选中图标变化)

而上方的页面切换有两个常用方案:

  1. 用之前说过的 navigation组件

  2. ViewPager2

参考 使用 NavigationUI 更新界面组件。 会发现用navigation组件实现这套东西时可以一行代码搞定。甚至在 创建新Android Activity 时提供了生成版本:

1.png

这本身就可以当个demo。包含了底部栏如何配置,NavHost怎么设置。而且其中的Fragment还有ViewModel

但有一个问题就是每次切换页面,Fragment都是重新构建的,就算数据可以在ViewModel活着,但是其他状态还是需要自己维护,比如列表滑动位置。

所以改用ViewPager2, 通过设置offscreenPageLimit来缓存页面。ViewPager2底层是RecyclerView, 用来替代之前的ViewPager, 尽力保持两版接口一致,同时解决之前遗留的很多棘手问题。

1. 底部导航栏:BottomNavigationView

  • 创建新的android Resource file, 类型选择menu。 添加menuItem

2.png

  • activity_main.xml添加BottomNavigationView控件,同时设置menu参数,之前设置的menuItem标题和图标会在底部栏直接显示。同时可以通过底部栏的itemIconTint等参数,设置选中态与未选中态的区别

3.png

2. 页面切换:

方案1: navigation

  • 添加 NavHost。如 navigation组件 中方式,添加导航图与目的地。

  • 注意idmenu中相同,navController通过id将导航图与底部栏链接

4.png

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

        val navHostFragment = supportFragmentManager.findFragmentById(R.id.mainNavHost) as NavHostFragment
        mainBtmNavView.setupWithNavController(navHostFragment.findNavController())
    }
}

点击底部栏便可以切换页面。

方案2: ViewPager2

点击第一页按钮,跳转新的Activity,将页面上方替换为ViewPager2, 其他不变。

  • ViewPager2 设置 adapter, 负责页面切换和组织(FragmentStateAdapter)。
  • ViewPager2 设置 offscreenPageLimit, 起到缓存作用
  • ViewPager2 注册 OnPageChangeCallback,页面滑动切换时回调,相当于ViewPagerOnPageChangeListener。 页面切换完成时,设置底部导航栏对应切换。
  • 如果不想滑动切换页面, 设置 ViewPager2isUserInputEnabled = false, 不必注册回调
  • 底部导航栏设置点击事件,ViewPager2跳转对应页面。

打印log验证页面是否保活。

class SecondaryActivity : AppCompatActivity() {

    private val fragments = arrayOf(Item1Fragment(), Item2Fragment(), Item3Fragment())
    private val itemIds = arrayOf(R.id.item1, R.id.item2, R.id.item3)

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

        secondaryVP.adapter = object : FragmentStateAdapter(supportFragmentManager, lifecycle) {
            override fun getItemCount(): Int = fragments.size
            override fun createFragment(position: Int): Fragment = fragments[position]
        }
        // 页面预加载
        secondaryVP.offscreenPageLimit = fragments.size

        // 若不想滑动切换页面时设置
        //secondaryVP.isUserInputEnabled = false
        secondaryVP.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageSelected(position: Int) {
                secondaryBtmNavView.selectedItemId = itemIds[position]
            }
        })

        secondaryBtmNavView.setOnNavigationItemSelectedListener {
            secondaryVP.currentItem = itemIds.indexOf(it.itemId)
            true
        }
    }
}

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值