Cal*_*Rai 8 vertical-scrolling android-fragments android-recyclerview android-nestedscrollview android-viewpager2
我正在使用带有两个垂直方向的片段的 ViewPager2。当用户向下滑动到第二个片段时,有一个 RecyclerView 在同一垂直方向滚动内容。
问题是当我滚动 RecyclerView 的内容时,有时 ViewPager2 捕获滚动事件,有时 RecyclerView 捕获滚动事件。
我希望这样,当用户滚动到 RecyclerView 的顶部时,ViewPager 仅在用户到达 RecyclerView 内容的顶部时才滑回第一个片段。
我试过使用 recyclerView.isNestedScrollingEnabled = false,但运气不佳。我也尝试将 RecyclerView 放入 NestedScrollView,但不推荐这样做,因为 RecyclerView 然后创建它需要的数据集的每个 ViewHolder,这显然效率不高。
Cal*_*Rai 18
所以......我能够通过阅读一些文档来弄清楚。我将在此处发布答案,以帮助其他遇到类似问题的人:
由于 ViewPager2 不支持嵌套滚动视图,与 NestedScrollView 不同,我们需要在布局中使用自定义包装器包装嵌套滚动视图,以便能够处理被嵌套滚动视图父级拦截的触摸和滑动事件。在我们的例子中,子元素是 RecyclerView,父元素是 ViewPager2。
您可以在此处找到包装类。只需将它添加到您的项目中,然后将您的可滚动视图包装在其中,类似于以下内容:
<NestedScrollableHost
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />
</NestedScrollableHost>
Run Code Online (Sandbox Code Playgroud)
这里有几件事需要注意:文档说这个解决方案不适用于 ViewPager 中其他可滚动视图中的可滚动视图。此解决方案仅适用于 ViewPager 的即时滚动视图。
另一个注意事项是包装类使用requestDisallowInterceptTouchEvent()来确保子可滚动视图告诉父级不要滚动,如果子级需要滚动。
小智 5
我得到的最好的解决方案是使用gestureDetector.SimpleOnGestureListenerinside on recyclerView.addOnItemTouchListener(this)。
步骤1:在OnCreate()方法中。该类GestureListener是在 Step-3 创建的。
gestureDetector = new GestureDetector(getActivity(), new GestureListener());
Run Code Online (Sandbox Code Playgroud)
步骤2:调用recyclerView.addOnItemTouchListener()方法。
recyclerView.addOnItemTouchListener(this);
Run Code Online (Sandbox Code Playgroud)
步骤3:创建GestureListener扩展的类GestureDetector.SimpleOnGestureListener。
public class GestureListener extends GestureDetector.SimpleOnGestureListener {
private final int Y_BUFFER = 10;
@Override
public boolean onDown(MotionEvent e) {
// Prevent ViewPager from intercepting touch events as soon as a DOWN is detected.
// If we don't do this the next MOVE event may trigger the ViewPager to switch
// tabs before this view can intercept the event.
Log.d("vp", "true1");
recyclerView.getParent().requestDisallowInterceptTouchEvent(true);
return super.onDown(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (Math.abs(distanceX) > Math.abs(distanceY)) {
Log.d("vp2", "true");
// Detected a horizontal scroll, allow the viewpager from switching tabs
recyclerView.getParent().requestDisallowInterceptTouchEvent(false);
} else if (Math.abs(distanceY) > Y_BUFFER) {
// Detected a vertical scroll prevent the viewpager from switching tabs
Log.d("vp3", "false");
recyclerView.getParent().requestDisallowInterceptTouchEvent(true);
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
}
Run Code Online (Sandbox Code Playgroud)
步骤 4:gestureDetector.onTouchEvent(e)从调用onInterceptTouchEvent()。
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
gestureDetector.onTouchEvent(e);
return false;
}
Run Code Online (Sandbox Code Playgroud)
更新
科特林版本
这是上一个答案的 kotlin 版本。
val gestureDetector = GestureDetector(requireActivity(), object: GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent?): Boolean {
rv.parent.requestDisallowInterceptTouchEvent(true)
return super.onDown(e)
}
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent?,
distanceX: Float,
distanceY: Float
): Boolean {
if (abs(distanceX) > abs(distanceY)) {
rv.parent.requestDisallowInterceptTouchEvent(false)
} else if (abs(distanceY) > 10) {
rv.parent.requestDisallowInterceptTouchEvent(true)
}
return super.onScroll(e1, e2, distanceX, distanceY)
}
})
rv.addOnItemTouchListener(object: RecyclerView.OnItemTouchListener {
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
gestureDetector.onTouchEvent(e)
return false
}
})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7955 次 |
| 最近记录: |