我有一个 RecyclerView(例如 rootRecyclerView
),它可以根据某些 API 响应具有不同类型的行。我实现了其中一个是水平的ViewPager2
另一种是通过水平 RecyclerView
实现的(例如,childRecyclerView
)。
rootRecyclerView 垂直滑动,而 viewPager2 和 childRecyclerView 水平滑动。
问题:
当我在屏幕上滑动时,如果滑动在viewPager2
上或childRecyclerView
,滑动必须水平完全笔直。否则,它们不会水平滚动;滑动由 rootRecyclerView
进行所以你会看到垂直运动。
所以,发生这种情况是因为您的拇指会沿弯曲/圆形方向移动,从而在 X 轴和 Y 轴上产生移动,因此 rootRecyclerView 会拦截滑动,从而产生这种不愉快的用户体验。
我确实尝试解决该问题,例如添加 OnItemTouchListener
像这样的 childRecyclerView:
private float Y_BUFFER = ViewConfiguration.get(getContext())
.getScaledPagingTouchSlop(); // 10;
private float preX = 0f;
private float preY = 0f;
childRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
if(e.getAction()==MotionEvent.ACTION_DOWN){
childRecyclerView.getParent().requestDisallowInterceptTouchEvent(true);
}
if(e.getAction() == MotionEvent.ACTION_MOVE){
if (Math.abs(e.getX() - preX) > Math.abs(e.getY() - preY)) {
childRecyclerView.getParent().requestDisallowInterceptTouchEvent(true);
} else if (Math.abs(e.getY() - preY) > Y_BUFFER) {
childRecyclerView.getParent().requestDisallowInterceptTouchEvent(false);
}
}
preX = e.getX();
preY = e.getY();
return false;
}
// ... rest of the code
它仅解决 childRecyclerView
的问题,但我无法解决ViewPager2
.
我也尝试过使用GestureDetector
如本answer link中所述,以及其他一些代码组合,但我无法使其工作。
有人可以帮助我吗?
最佳答案
好吧,经过一番研究,我得出的结论是替换我的 ViewPager2
与 recyclerView
这将“表现得像”viewPager :/.
首先我更换了我的 viewPager2
与水平recyclerView
。要使其表现得像一个viewpager,请使用 SnapHelper
.
RecyclerView childRecyclerView2 = findViewById(R.id.previously_viewPager);
// other init like setup layout manager, adapter etc
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(replacedRecyclerView); // <-- this makes out rv behave like a viewPager
之后,您必须添加 OnItemTouchListener
并覆盖onInterceptTouchEvent
就像我问题中的代码段:
childRecyclerView2.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
// same as the code segment in the question,
//so skipping this part.
//just copy it from my question
}
// ...
}
可选:
在viewPager2中,可以通过 getCurrentItem()
获取当前焦点,但是由于我们已经用recyclerview替换了viewpager2,所以我们没有这个方法。因此,我们需要实现我们自己的等效版本。如果你是 Kotlin 爱好者,可以直接跳到 reference 2并跳过这部分。如果您需要的话,这里是 java 版本,不过我会跳过解释。
创建SnapHelperExt.java
public class SnapHelperExt {
public SnapHelperExt(){}
public int getSnapPosition(RecyclerView recyclerView, SnapHelper snapHelper){
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
View snapView = snapHelper.findSnapView(layoutManager);
if (snapView != null) {
return layoutManager.getPosition(snapView);
}else{
return -1;
}
}
}
接下来创建一个接口(interface)OnSnapPositionChangeListener
作为我们的听众:
public interface OnSnapPositionChangeListener {
void onSnapPositionChange(int position);
}
之后,创建 SnapOnScrollListener.java
:
public class SnapOnScrollListener extends RecyclerView.OnScrollListener {
public enum Behavior {
NOTIFY_ON_SCROLL,
NOTIFY_ON_SCROLL_STATE_IDLE
}
private SnapHelperExt snapHelperExt;
private SnapHelper snapHelper;
private Behavior behavior;
private OnSnapPositionChangeListener onSnapPositionChangeListener;
private int snapPosition = RecyclerView.NO_POSITION;
public SnapOnScrollListener(SnapHelper snapHelper, Behavior behavior, OnSnapPositionChangeListener onSnapPositionChangeListener){
this.snapHelper = snapHelper;
this.behavior = behavior;
this.onSnapPositionChangeListener = onSnapPositionChangeListener;
this.snapHelperExt = new SnapHelperExt();
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (behavior == Behavior.NOTIFY_ON_SCROLL) {
maybeNotifySnapPositionChange(recyclerView);
}
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (behavior == Behavior.NOTIFY_ON_SCROLL_STATE_IDLE
&& newState == RecyclerView.SCROLL_STATE_IDLE) {
maybeNotifySnapPositionChange(recyclerView);
}
}
private void maybeNotifySnapPositionChange(RecyclerView recyclerView){
int prevPosition = this.snapHelperExt.getSnapPosition(recyclerView, snapHelper);
boolean snapPositionIsChanged = (this.snapPosition!=prevPosition);
if(snapPositionIsChanged){
onSnapPositionChangeListener.onSnapPositionChange(prevPosition);
this.snapPosition = prevPosition;
}
}
}
最后,这样使用:
SnapOnScrollListener snapOnScrollListener = new SnapOnScrollListener(
snapHelper,
SnapOnScrollListener.Behavior.NOTIFY_ON_SCROLL,
position -> {
Log.e(TAG, "currently focused page no = "+position);
// your code here, do whatever you want
}
);
childRecyclerView2.addOnScrollListener(snapOnScrollListener);
引用文献:
关于java - 如何解决垂直 RecyclerView 内水平 ViewPager2 和 RecyclerView 的滚动问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60313270/