2

我在我的应用程序中使用导航组件,使用谷歌高级示例(此处)。我的问题是返回片段时,滚动位置不会丢失,但它会重新排列项目并移动最高可见项目,以便这些项目的顶部与 recyclerview 的顶部对齐。请看这个:

在此处输入图像描述

在进入下一个片段之前:

在此处输入图像描述

然后回到片段:

在此处输入图像描述

这个问题很重要,因为有时单击的项目会下降并且直到向下滚动才能看到。如何防止这种行为?

请考虑:

  • 如果使用导航组件更改片段,则存在此问题。如果启动片段使用supportFragmentManager.beginTransaction()或启动另一个活动,然后转到该片段就可以了。但是如果我使用导航组件导航到另一个片段,则存在此问题。(可能是因为重新创建片段)

  • 如果在 ViewPager 中使用片段也存在此问题。即,recyclerView 位于使用 ViewPagerAdapter 处理的片段中,而 viewPager 位于使用 Navigation 组件打开的 HomeFragment 中。如果 recyclerView 在 HomeFragment 中没有问题。

  • LinearLayoutManager 没问题。仅使用 StaggeredGridLayoutManager。

  • 如果使用 ViewPager2 和 FragmentStatePagerAdapter 没有区别

  • 我试图防止重新创建片段(通过这个解决方案)但没有解决。

更新:你可以从 这里克隆有这个问题的项目

4

2 回答 2

1

当您从一个片段导航到另一个片段时,导航组件的行为是正常的。我的意思是,onDestroyView()前一个片段的方法被执行了,所以这意味着你的视图被破坏了,但片段没有被破坏。记住片段有两个生命周期,一个用于片段,另一个用于视图,有一个关于它的视频。

此外,在问题跟踪器中注册了一些问题,以避免在某些情况下出现这种行为以及 GitHub 问题:

问题是当你有很重的片段需要重新创建时,更容易不破坏它而只添加一个片段。因此,当您返回时,它不会被重新创建。但是,因为这种行为不是导航组件的一部分。

解决方案

  • 最简单的解决方案是不使用导航组件并使用传统方式,因为您可以看到这在您的用例中非常有效。

  • 您可以仅针对此用例使用传统方式,而将导航组件用于其他情况。

  • 您可以在活动中扩充此视图。所以你正在添加联合国活动

  • 但是如果前面的树选项是不可能的。您可以尝试以下方法:

    • 如果您使用的是 viewModel,则可以使用SaveState。基本上,它可以保存片段中的数据,它就像一个地图数据结构,因此您可以保存列表或回收器视图中的位置。当回到这个片段时,从这个 saveState 对象中获取位置并使用scrollToPosition方法来添加实际位置。
    • 回收站视图具有恢复位置的方法。您可以查看其用例,因为首先您需要数据,然后添加实际位置,有关更多详细信息,您可以访问此链接。当您丢失内存并且需要使用异步数据重新创建回收器视图时,此回收器视图配置也很有用。

最后,如果您想了解更多有关片段如何与导航组件一起使用的信息,可以查看此链接

于 2021-01-05T13:46:11.817 回答
1

使用Navigation Component++ViewPager时,重新创建时返回StaggeredGridLayoutManager错误。recyclerView.computeVerticalScrollOffset()Fragment

一般来说,支持库中捆绑的所有布局管理器都已经知道如何保存和恢复滚动位置,但是在这种情况下,我们必须对此负责。

class TestFragment : Fragment(R.layout.fragment_test) {

    private val testListAdapter: TestListAdapter by lazy {
        TestListAdapter()
    }

    private var layoutManagerState: Parcelable? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        postListView.apply {
            layoutManager = StaggeredGridLayoutManager(
                2, StaggeredGridLayoutManager.VERTICAL
            ).apply {
                gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
            }
            setHasFixedSize(true)

            adapter = testListAdapter
        }

        testListAdapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT

    }

    override fun onPause() {
        saveLayoutManagerState()
        super.onPause()
    }

    override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
        restoreLayoutManagerState()
    }

    private fun restoreLayoutManagerState () {
        layoutManagerState?.let { postListView.layoutManager?.onRestoreInstanceState(it) }
    }

    private fun saveLayoutManagerState () {
        layoutManagerState = postListView.layoutManager?.onSaveInstanceState()
    }
}

源代码:https ://github.com/dautovicharis/MyStaggeredListSample/tree/q_65539771

于 2021-01-06T13:13:35.670 回答