CoordinatorLayout 中的 ViewPager(用于粘性 header 目的)导致滚动中断
ViewPager within a CoordinatorLayout (for sticky header purposes) leads to broken scrolling
在此处演示问题的测试应用程序:https://github.com/jstubing/ViewPagerTest
我正在使用 CoordinatorLayout/AppBarLayout 组合在可滚动页面中实现粘性 header。在页面的最底部是一个 ViewPager2。当我滑动到新的 ViewPager
页面时,内容会异步加载并填充 ViewPager 中的 RecyclerView
。这一切都很好。
当我滑动到新的 ViewPager
页面时出现问题。此时,内容加载并呈现良好,但我无法再在 ViewPager 之外启动滚动。换句话说,在“上页内容”部分(参见 XML)上下滑动没有任何作用。
但是,在 ViewPager 中可以上下滚动。如果我在 ViewPager 中向上或向下滚动,或者甚至只是点击一次 ViewPager,它会修复所有问题,我可以再次从 ViewPager
.
外部启动滚动
我尝试切换到原始 ViewPager
而不是 ViewPager2,它确实更可靠,但问题仍然时常发生。
有什么办法可以解决这个问题吗?最终,我只想能够在 ViewPager
页面之间滑动,并让整个 activity 页面保持可滚动。我很困惑为什么我一开始就失去了滚动能力,为什么点击 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>
The problem occurs when I swipe to a new ViewPager page. At this
point, the content loads and renders fine but I am no longer able to
initiate a scroll outside of the ViewPager.
I am again able to initiate a scroll from outside of the 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);
}
我们不能完全禁用嵌套滚动,因为这会严重影响外部滚动,因此,我们可以通过包裹 ViewPager
:
的 NestedScrollView
来操作它
<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>
在此处演示问题的测试应用程序:https://github.com/jstubing/ViewPagerTest
我正在使用 CoordinatorLayout/AppBarLayout 组合在可滚动页面中实现粘性 header。在页面的最底部是一个 ViewPager2。当我滑动到新的 ViewPager
页面时,内容会异步加载并填充 ViewPager 中的 RecyclerView
。这一切都很好。
当我滑动到新的 ViewPager
页面时出现问题。此时,内容加载并呈现良好,但我无法再在 ViewPager 之外启动滚动。换句话说,在“上页内容”部分(参见 XML)上下滑动没有任何作用。
但是,在 ViewPager 中可以上下滚动。如果我在 ViewPager 中向上或向下滚动,或者甚至只是点击一次 ViewPager,它会修复所有问题,我可以再次从 ViewPager
.
我尝试切换到原始 ViewPager
而不是 ViewPager2,它确实更可靠,但问题仍然时常发生。
有什么办法可以解决这个问题吗?最终,我只想能够在 ViewPager
页面之间滑动,并让整个 activity 页面保持可滚动。我很困惑为什么我一开始就失去了滚动能力,为什么点击 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>
The problem occurs when I swipe to a new ViewPager page. At this point, the content loads and renders fine but I am no longer able to initiate a scroll outside of the ViewPager.
I am again able to initiate a scroll from outside of the 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);
}
我们不能完全禁用嵌套滚动,因为这会严重影响外部滚动,因此,我们可以通过包裹 ViewPager
:
NestedScrollView
来操作它
<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>