Android 当子recyclerview滚动到最后一项时禁用ViewPager分页

Android 当子recyclerview滚动到最后一项时禁用ViewPager分页,android,android-fragments,android-viewpager,android-recyclerview,Android,Android Fragments,Android Viewpager,Android Recyclerview,我有一个viewpager,在其中一个片段中,我有两个单独的片段,分别包含一个垂直和一个水平的recyclerview 当我将水平循环视图滚动到最后一项并尝试进一步滑动时,viewpager将滚动到下一页。我不希望这种情况发生。当我试图覆盖水平循环视图时,我想禁用viewpager的分页 但是,当我在其他地方滑动时,我不想禁用viewpager的分页。例如,如果我要滑动垂直recyclerview或父片段中的任何空白,它仍然会导致viewpager更改页面 我读过,如何禁用viewpager的分

我有一个viewpager,在其中一个片段中,我有两个单独的片段,分别包含一个垂直和一个水平的recyclerview

当我将水平循环视图滚动到最后一项并尝试进一步滑动时,viewpager将滚动到下一页。我不希望这种情况发生。当我试图覆盖水平循环视图时,我想禁用viewpager的分页

但是,当我在其他地方滑动时,我不想禁用viewpager的分页。例如,如果我要滑动垂直recyclerview或父片段中的任何空白,它仍然会导致viewpager更改页面

我读过,如何禁用viewpager的分页。还有一个类似的地方是有一个子viewpager,但是我还没有成功地尝试用一个水平的recyclerview复制它

以下是一些结构:

允许我禁用分页的自定义viewpager(从上面的第一个SO链接获取):

对于水平循环视图,我设置了一个ontouchlistener(类似于上面的第二个SO链接):

额外观察:我注意到,有时如果在刷卡之前长按水平循环视图,它将不会进入viewpager的下一页。但是,如果我快速滑动,viewpager将转到下一页

有人知道这样做的正确方法吗

感谢您的帮助。

这是解决方案

requestDisallowInterceptTouchEvent()
此方法不允许父对象移动。它会停止viewpager触摸事件

horizontalRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            int action = e.getAction();
            switch (action) {
                case MotionEvent.ACTION_MOVE:
                    rv.getParent().requestDisallowInterceptTouchEvent(true);
                    break;
            }
            return false;
        }

        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e) {

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

        }
    });

为了处理垂直滚动不再工作的问题,我改为:

为RecyclerView项目创建触摸侦听器

mGestureDetector = new GestureDetector(itemView.getContext(), new GestureListener());

/**
 * Prevents the view pager from switching tabs when scrolling the carousel
 */
private class TouchListener implements RecyclerView.OnItemTouchListener {

  @Override
  public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
      mGestureDetector.onTouchEvent(e);
      return false;
  }
}
并实现一个手势监听器,当检测到水平滚动时,该监听器不允许触摸事件:

private class GestureListener extends 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.
        mRecyclerView.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)) {
            // Detected a horizontal scroll, prevent the viewpager from switching tabs
            mRecyclerView.requestDisallowInterceptTouchEvent(true);
        } else if (Math.abs(distanceY) > Y_BUFFER) {
            // Detected a vertical scroll of large enough magnitude so allow the the event
            // to propagate to ancestor views to allow vertical scrolling.  Without the buffer
            // a tab swipe would be triggered while holding finger still while glow effect was
            // visible.
            mRecyclerView.requestDisallowInterceptTouchEvent(false);
        }
        return super.onScroll(e1, e2, distanceX, distanceY);
    }
}

以防有人和我有同样的问题

如果层次结构中有一个
SwipeRefreshLayout
,并且它的子级确实为
ViewCompat.isNestedScrollEnabled()
(在我的例子中是
FrameLayout
),这将不起作用,因为在它传递
RequestDisallowerWinterCeptTouchEvent()
之前签入了
SwipeRefreshLayout

我花了一点时间调试,但下面是来自
SwipeRefreshLayout
的具体检查:

if ((VERSION.SDK_INT >= 21 || !(this.mTarget instanceof AbsListView)) && (this.mTarget == null || ViewCompat.isNestedScrollingEnabled(this.mTarget))) {
    super.requestDisallowInterceptTouchEvent(b);
}

通过删除
FrameLayout
,将
SwipeRefreshLayout
的子对象设置为
NestedScrollView
,我可以让Shabbir Dhangot的答案生效。

对于kotlin,您可以尝试此解决方案

 horizontalRecyclerView.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
        override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
            val action = e.action
            when (action) {
                MotionEvent.ACTION_MOVE -> rv.parent.requestDisallowInterceptTouchEvent(true)
            }
            return false
        }

        override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
        override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
    })

找到任何解决方案。我正在寻找同样的问题。任何解决方法,请帮助。提前谢谢!这一个工作正常,但recyclerview滚动到最后一项。应该显示第一项。我必须使用请求。。。对于所有事件,都要真正防止这种行为。公共布尔值onInterceptTouchEvent(RecyclerView rv,MotionEvent e){rv.getParent().RequestDisallowWinterceptTouchEvent(true);返回false;}其工作状态。。但触摸horizontalRecyclerView时垂直滚动不起作用。有没有解决此问题的方法?不阻止垂直滚动添加:布尔值isVerticalScroll=Math.abs(dy)>Math.abs(dx);如果(!isVerticalScroll){rv.getParent().RequestDisallowWinterCeptTouchEvent(true)}。如何获取dy和dx的逻辑可以在RecyclerView源代码中找到。
if ((VERSION.SDK_INT >= 21 || !(this.mTarget instanceof AbsListView)) && (this.mTarget == null || ViewCompat.isNestedScrollingEnabled(this.mTarget))) {
    super.requestDisallowInterceptTouchEvent(b);
}
 horizontalRecyclerView.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
        override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
            val action = e.action
            when (action) {
                MotionEvent.ACTION_MOVE -> rv.parent.requestDisallowInterceptTouchEvent(true)
            }
            return false
        }

        override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {}
        override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
    })