【问题标题】:BottomNavigationView lags on fragment transactionBottomNavigationView 滞后于片段事务
【发布时间】: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 的方式?

【问题讨论】:

    标签: android android-fragments kotlin material-design bottomnavigationview


    【解决方案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 等使它们更轻...
    猜你喜欢
    • 2015-07-05
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    • 2022-10-12
    • 1970-01-01
    • 2012-01-12
    相关资源
    最近更新 更多