问题描述
我在我的应用程序中使用导航组件,使用 google Advanced Sample(here)。 我的问题是当回到片段时,滚动位置不会丢失,但它会重新排列项目并移动最高可见项目,以便这些项目的顶部与 recyclerview 的顶部对齐。请看这个:
在进入下一个片段之前:
然后回到片段:
这个问题很重要,因为有时点击的项目会下降,直到向下滚动才能看到。 如何防止这种行为?
请考虑:
-
如果使用导航组件更改片段,则存在此问题。如果使用
supportFragmentManager.beginTransaction()
启动片段或启动另一个活动,然后转到此片段就可以了。但是如果我使用导航组件导航到另一个片段,则存在此问题。(可能是因为重新创建片段) -
如果在 ViewPager 中使用片段也会存在这个问题。即 recyclerView 位于使用 ViewPagerAdapter 处理的片段中,而 viewPager 位于使用导航组件打开的 HomeFragment 中。如果 recyclerView 在 HomeFragment 中就没有问题。
-
linearlayoutmanager 没问题。仅适用于 StaggeredGridLayoutManager。
-
使用 ViewPager2 和 FragmentStatePagerAdapter 没有区别
更新: 您可以从 here
克隆存在此问题的项目解决方法
当您从一个片段导航到另一个片段时,导航组件的行为是正常的。我的意思是,前一个片段的 onDestroyView()
方法被执行,所以这意味着你的视图被破坏了,而不是片段。记住片段有两个生命周期,一个用于片段,另一个用于视图,关于它有一个video。
此外,为了在某些情况下避免这种行为和 GitHub 问题,问题跟踪器中注册了问题:
- https://issuetracker.google.com/issues/127932815
- https://github.com/android/architecture-components-samples/issues/530
问题是,当你有很重的片段需要重新创建时,不破坏它而只添加一个片段会更容易。因此,当您返回时,它不会重新创建。但是,这种行为不是导航组件的一部分。
解决方案
-
最简单的解决方案是不使用导航组件并以传统方式工作,因为您可以看到这在您的用例中非常有效。
-
您可以仅针对此用例使用传统方式,而针对其他情况使用导航组件。
-
您可以在活动中扩充此视图。所以你正在添加联合国活动
-
但是如果之前的树选项是不可能的。您可以尝试以下操作:
最后,如果你想了解更多关于 fragment 如何与导航组件一起工作的信息,你可以看这个link
,使用 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