使用导航组件保存 RecyclerView 的滚动

Posted

技术标签:

【中文标题】使用导航组件保存 RecyclerView 的滚动【英文标题】:Saving scroll of RecyclerView with navigation component 【发布时间】:2020-04-13 11:28:03 【问题描述】:

我在我的应用程序中使用带有 BottomNavigationView 的导航组件。它在 4 个目的地之间切换,其中一个包含一个带有 RecyclerView 的片段,其中包含数百个项目。当我使用后退按钮时,RecyclerView 会恢复到之前的滚动位置。但是当我使用 BottomNavigationView 在目的地之间切换时,它不会恢复到以前的位置并重置到 RecyclerView 的顶部。这是我试图阻止的代码

    override fun onPause() 
    super.onPause()

    lastScrollPos = linearLayoutManager.findFirstVisibleItemPosition()
    

    override fun onResume() 
        super.onResume()

        card_recyclerView.layoutManager?.scrollToPosition(lastScrollPos)

这行不通 将 RecyclerView 恢复到正确位置的最佳方法是什么?

【问题讨论】:

【参考方案1】:

它不滚动到上一个位置的原因是navController在与bottomNavigation一起使用时重新创建了片段(使用替换)。

保存滚动状态的一种简单方法是将layoutManager 状态存储在onDestroyView 中并将其恢复到onCreateView,与scrollToPosition 不同,此方法将滚动到确切位置,当NavController 重新创建片段。

我在另一个线程https://***.com/a/66940957/2102794发布了完整代码

【讨论】:

【参考方案2】:

这可以通过将ScrollView 的Y 轴位置保存在成员变量中并在onCreateView() 中恢复来完成。这是有效的,因为成员变量没有被破坏。

class DiscoverDataFragment : BaseFragment() 
    private var loaded = false
    private var scrollPos = 0
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
        return inflater.inflate(R.layout.fragment_discover_data, container, false)
    
    
    override fun onCreateBind() 
        super.onCreateBind()  
        if (!loaded) 
            // Load views here
            loaded = true
        
        
        if (scrollPos > 0) 
            scrollDiscoverData.scrollY = scrollPos
        
    
        setScrollListener()
    
    
    private fun setScrollListener() 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
            scrollDiscoverData.setOnScrollChangeListener  v, scrollX, scrollY, oldScrollX, oldScrollY ->
            scrollPos = scrollY
        
    

【讨论】:

【参考方案3】:

你必须在片段生命周期之外初始化适配器,例如

class MyFragment : Fragment() 

private val myViewModel by viewModel<MyViewModel>()
private lateinit var myAdapter : MyAdapter

override fun onActivityCreated(savedInstanceState: Bundle?) 
    super.onActivityCreated(savedInstanceState)
    myAdapter = MyAdapter()
    Log.d("checkListData", myAdapter.currentList.toString())
    myViewModel.someListData.observe(viewLifecycleOwner) listData ->
        myAdapter.submitList(listData)
    

【讨论】:

哦,普通人。先学android框架。这是一种反模式,因为它是一个很大的内存泄漏。

以上是关于使用导航组件保存 RecyclerView 的滚动的主要内容,如果未能解决你的问题,请参考以下文章

Android10.5 滚动视图(RecyclerView)

RecyclerView 适配器中的导航组件

Android下拉刷新滚动到底部自动加载更多RecyclerView组件

我应该使用 ScrollView 还是 RecyclerView 在片段中滚动?

组件RecyclerView的应用

从其他活动返回到同一片段时,如何保存和恢复片段中 RecyclerView 的滚动位置?