问题
I'm using a ViewPager2 with two fragments in a vertical orientation. When the user swipes down to the second fragment, there is a RecyclerView that scrolls content in the same vertical direction.
The issue is that when I scroll the contents of the RecyclerView, sometimes the ViewPager2 catches the scroll events and sometimes the RecyclerView catches the scroll events.
I would like it so that when the user is scrolling to the top of the RecyclerView, the ViewPager only swipes back up to the first fragment when the user has reached the top of the contents in the RecyclerView.
I've tried using recyclerView.isNestedScrollingEnabled = false
without much luck. I also tried putting the RecyclerView into a NestedScrollView, but that is not recommended because the RecyclerView then creates every single ViewHolder it needs for the dataset and that is obviously not efficient.
回答1:
So...I was able to figure it out by just reading some documentation 😅. I'll post the answer here so that it helps anyone else having a similar issue:
Since ViewPager2 does not supported nested scroll views very well, unlike NestedScrollView, we need to wrap our nested scrollview with a custom wrapper in our layout to be able to handle the touch and swipe events that are getting intercepted by our nested scroll views parent. In our case, the child would be the RecyclerView and the parent would be the ViewPager2.
You can find the wrapper class here. Simply add it to your project and then wrap your scrollable view in it, similar to below:
<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>
There are a couple things to note here: The documentation says that this solution will not work for scrollable views that are within other scrollable views within the ViewPager. This solution only works for immediate scroll views of the ViewPager.
Another note is that the wrapper class uses the requestDisallowInterceptTouchEvent()
to make sure that the child scrollable view tells the parent not to scroll if the child needs to scroll instead.
回答2:
The best solution till i get is use gestureDetector.SimpleOnGestureListener inside on recyclerView.addOnItemTouchListener(this).
Step-1: In OnCreate() method
gestureDetector = new GestureDetector(getActivity(), new GestureListener());
Step-2: Implement recyclerView addonitemtouchlistenr method-
recyclerView.addOnItemTouchListener(this);
Step-3: Create class GestureListener that extends 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);
}
}
Step-4: call gestureDetector.onTouchEvent(e) from onInterceptTouchEvent().
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
gestureDetector.onTouchEvent(e);
return false;
}
来源:https://stackoverflow.com/questions/60640368/vertical-viewpager2-with-recyclerview-scrolling-issue