BottomNavigationView 滞后于片段事务

Posted

技术标签:

【中文标题】BottomNavigationView 滞后于片段事务【英文标题】:BottomNavigationView lags on fragment transaction 【发布时间】:2019-02-09 19:51:54 【问题描述】:

问题

我在我的一个活动中使用来自 android 设计支持库的 BottomNavigationView,以及每个导航项的片段。

每次我在栏上选择一个项目时,我都会进行一次片段事务,如下面的 sn-p (为简洁起见,删除了部分代码):

private var fragmentToSet: Fragment? = null

private val onNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener  item ->

    fragmentToSet = when (item.itemId) 
        // Choose fragment based on selection
        // ...
    

// ...

supportFragmentManager.beginTransaction()
                .replace(R.id.container, fragmentToSet)
                .commit()

问题是...底栏动画变得超级滞后,只有在片段完全加载并显示在屏幕上后才能完成。

这个问题is not exactly new,因为它也可能在使用导航菜单时发生,但至少可以通过使用DrawerLayout.DrawerListener 解决它,并且只有在抽屉关闭后才执行实际的片段事务。

到目前为止我已经尝试过什么

我尝试“缓存”片段,保留它们的引用以避免每次都重新创建对象(例如MyFragment.newInstance()),但这不起作用。

我也尝试使用处理程序,这有点解决了问题,但它可能会导致我出现异常in some cases。类似于下面的 sn-p:

handler.postDelayed(changeFragment(fragmentToSet!!), 200)

有没有办法在不使用处理程序(或其他异步调用)的情况下解决此问题,类似于使用导航菜单时this solution 的方式?

【问题讨论】:

【参考方案1】:

我通过使用片段管理器隐藏和显示片段来处理这种情况。我写了一个示例代码来处理它,如下所示。

class MainActivity : BaseActivity() 

    private val homeFragment = HomeFragment.newInstance()
    private val categoryFragment = CategoryFragment.newInstance()
    private val searchFragment = SearchFragment.newInstance()

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

        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
        navigation.menu.findItem(R.id.navigation_home).isChecked = true

        supportFragmentManager.beginTransaction()
                .add(R.id.containerFrameLayout, homeFragment)
                .add(R.id.containerFrameLayout, categoryFragment)
                .add(R.id.containerFrameLayout, searchFragment)
                .commit()
        setTabStateFragment(TabState.HOME).commit()
    

    override fun onBackPressed() 
        if (supportFragmentManager.backStackEntryCount > 0 || !homeFragment.isHidden) 
            super.onBackPressed()
         else 
            setTabStateFragment(TabState.HOME).commit()
            navigation.menu.findItem(R.id.navigation_home).isChecked = true
        
    

    private fun setTabStateFragment(state: TabState): FragmentTransaction 
        supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
        val transaction = supportFragmentManager.beginTransaction()
        transaction.setCustomAnimations(R.anim.fragment_enter, R.anim.fragment_exit)
        when (state) 
            TabState.HOME -> 
                transaction.show(homeFragment)
                transaction.hide(categoryFragment)
                transaction.hide(searchFragment)
            
            TabState.CATEGORY -> 
                transaction.hide(homeFragment)
                transaction.show(categoryFragment)
                transaction.hide(searchFragment)
            
            TabState.SEARCH -> 
                transaction.hide(homeFragment)
                transaction.hide(categoryFragment)
                transaction.show(searchFragment)
            
        
        return transaction
    

    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener  item ->
        when (item.itemId) 
            R.id.navigation_home -> 
                setTabStateFragment(TabState.HOME).commit()
                return@OnNavigationItemSelectedListener true
            
            R.id.navigation_category -> 
                setTabStateFragment(TabState.CATEGORY).commit()
                return@OnNavigationItemSelectedListener true
            
            R.id.navigation_search -> 
                setTabStateFragment(TabState.SEARCH).commit()
                return@OnNavigationItemSelectedListener true
            
        
        false
    

    internal enum class TabState 
        HOME,
        CATEGORY,
        SEARCH,
    


【讨论】:

这确实很有趣!我会实现它并测试它。谢谢! @Mauker:如果它适合你,请接受答案,伙计;) 当然!给我一些,我会回来的。再次感谢。 它解决了 90% 的问题。这是我注意到的:第一次点击导航栏时,它仍然滞后,但在第二次之后它会产生奇迹。我相信如果我改变创建视图的方式,这可以解决。但由于它适用于“第二次点击”,我将其标记为已解决。绝妙的解决方案。 谢谢你。我认为您应该修改与片段视图相关的代码,并尝试通过使用 RecyclerView、ViewStub 等使它们更轻...

以上是关于BottomNavigationView 滞后于片段事务的主要内容,如果未能解决你的问题,请参考以下文章

CPLD和FPGA的编程和配置都有哪些方式

BottomNavigationView 的标题颜色为渐变

安卓。具有单一活动方法的 BottomNavigationView

BottomNavigationView - 阴影和波纹效果

如何使用 material.BottomNavigationView 设置 Jetpack 导航

BottomNavigationView 的使用