当子recyclelerview滚动到最后一个项

时间:2016-07-19 18:55:11

标签: android android-fragments android-viewpager android-recyclerview

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

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

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

我读了in this SO question,如何禁用viewpager的分页。同样 this SO question也是类似的,因为有一个子viewpager,但是我没有成功尝试使用水平Recyclerview复制它。

这是一些结构:

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

public class CustomViewPager extends ViewPager {

private boolean enabled;

public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.enabled = true;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (this.enabled) {
        return super.onTouchEvent(event);
    }

    return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (this.enabled) {
        return super.onInterceptTouchEvent(event);
    }

    return false;
}

public void setPagingEnabled(boolean enabled) {
    this.enabled = enabled;
} }

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

horizontalRecyclerView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch(event.getAction()){
                        case MotionEvent.ACTION_MOVE:
                            customViewPager.setPagingEnabled(false);
                            break;
                        case MotionEvent.ACTION_UP:
                            customViewPager.setPagingEnabled(true);
                            break;
                    }
                    return false;
                }
            });

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

有谁知道这样做的正确方法?

感谢任何帮助。

4 个答案:

答案 0 :(得分:18)

这是解决方案。

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) {

        }
    });

答案 1 :(得分:1)

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

为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;
  }
}

实现一个GestureListener,当检测到水平滚动时不允许触摸事件:

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);
    }
}

答案 2 :(得分:0)

以防万一有人遇到与我相同的问题。

如果您在层次结构中有一个SwipeRefreshLayout,并且其子对象确实为ViewCompat.isNestedScrollEnabled()返回了true(在我的情况下为FrameLayout),则由于检入{ {1}}在通过SwipeRefreshLayout之前。

请我调试一下,但这是来自requestDisallowInterceptTouchEvent()的特定检查:

SwipeRefreshLayout

通过删除if ((VERSION.SDK_INT >= 21 || !(this.mTarget instanceof AbsListView)) && (this.mTarget == null || ViewCompat.isNestedScrollingEnabled(this.mTarget))) { super.requestDisallowInterceptTouchEvent(b); } ,使FrameLayout的孩子成为SwipeRefreshLayout,我可以得到Shabbir Dhangot的答案。

答案 3 :(得分:0)

对于 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) {}
    })