问题描述
在此处演示问题的测试应用:https://github.com/jstubing/ViewPagerTest
我使用 CoordinatorLayout/AppBarLayout 组合在可滚动页面中实现粘性标题。在页面的最底部是一个 ViewPager2。当我滑动到新的 ViewPager
页面时,内容会异步加载并在 ViewPager 中填充 RecyclerView
。这一切都很好。
当我滑动到新的 ViewPager
页面时出现问题。此时,内容加载并呈现良好,但我不再能够在 ViewPager 之外启动滚动。换句话说,在“UPPER PAGE CONTENT”部分(请参阅 XML)中上下滑动没有任何作用。
但是,在 ViewPager 中上下滚动确实有效。如果我在 ViewPager 中向上或向下滚动,或者甚至只是点击 ViewPager 一次,它都会修复所有内容,并且我再次能够从 ViewPager
外部启动滚动。
我尝试切换到原来的 ViewPager
而不是 ViewPager2,它确实更可靠,但问题仍然经常发生。
有什么想法可以解决这个问题吗?最终,我只想能够在 ViewPager
页面之间滑动并使整个活动保持可滚动。我很困惑为什么我首先失去了滚动能力,为什么点击 ViewPager
可以修复它。
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:elevation="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
app:elevation="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
app:layout_scrollFlags="scroll">
<!-- UPPER PAGE CONTENT -->
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- Sticky header -->
<include
android:id="@+id/sticky_header"
layout="@layout/sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/events_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
解决方法
当我滑动到新的 ViewPager 页面时出现问题。在这 点,内容加载并呈现良好,但我不再能够 在 ViewPager 之外启动滚动。
我再次能够从 ViewPager 外部启动滚动。
因此,问题现在仅限于 ViewPager
。很可能是因为 ViewPager2
支持通过其内部 RecyclerView
嵌套滚动(我不是指页面的 RecyclerView
,而是使 ViewPager
在内部起作用的那个。
所以,首先我们需要禁用 ViewPager2
的嵌套滚动:
科特林:
viewPager.children.find { it is RecyclerView }?.let {
(it as RecyclerView).isNestedScrollingEnabled = false
}
Java:
for (int i = 0; i < viewPager.getChildCount(); i++) {
View child = viewPager.getChildAt(i);
if (child instanceof RecyclerView)
child.setNestedScrollingEnabled(false);
}
我们不能完全禁用嵌套滚动,因为这会严重影响外部滚动,因此,我们可以通过包装 NestedScrollView
的 ViewPager
进行操作:
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/events_pager"
android:layout_width="match_parent"
android:layout_height="match_parent />
</androidx.core.widget.NestedScrollView>