在recyclerview

时间:2015-10-31 17:42:36

标签: android android-recyclerview

我需要在recyclerview中检测滚动的开始/结束和方向。滚动侦听器有两种方法:onScrolled()onScrollStateChanged()。滚动开始后调用第一个方法(实际上是调用onScrolled()而不是onScrolling())。第二种方法提供有关州的信息,但我没有方向信息。我怎样才能实现目标?

8 个答案:

答案 0 :(得分:71)

步骤1您可以创建一个扩展RecyclerView.OnScrollListener的类并覆盖这些方法

public class CustomScrollListener extends RecyclerView.OnScrollListener {
    public CustomScrollListener() {
    }

    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        switch (newState) {
            case RecyclerView.SCROLL_STATE_IDLE:
                System.out.println("The RecyclerView is not scrolling");
                break;
            case RecyclerView.SCROLL_STATE_DRAGGING:
                System.out.println("Scrolling now");
                break;
            case RecyclerView.SCROLL_STATE_SETTLING:
                System.out.println("Scroll Settling");
                break;

        }

    }

    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        if (dx > 0) {
            System.out.println("Scrolled Right");
        } else if (dx < 0) {
            System.out.println("Scrolled Left");
        } else {
            System.out.println("No Horizontal Scrolled");
        }

        if (dy > 0) {
            System.out.println("Scrolled Downwards");
        } else if (dy < 0) {
            System.out.println("Scrolled Upwards");
        } else {
            System.out.println("No Vertical Scrolled");
        }
    }
}

第2步 - 因为不推荐使用setOnScrollListener最好使用addOnScrollListener

 mRecyclerView.addOnScrollListener(new CustomScrollListener());

答案 1 :(得分:35)

请参阅onScrollStateChanged(int state)的文档。 三个可能的值是:

  • SCROLL_STATE_IDLE:没有滚动。
  • SCROLL_STATE_DRAGGING:用户在屏幕上拖动手指(或者以编程方式完成。
  • SCROLL_STATE_SETTLING:用户抬起手指,动画现在正在放慢速度。

因此,如果您想要检测滚动的开始和结束时间,那么您可以创建如下内容:

public void onScrollStateChanged(int state) {
    boolean hasStarted = state == SCROLL_STATE_DRAGGING;
    boolean hasEnded = state == SCROLL_STATE_IDLE;
}

答案 2 :(得分:3)

最简单的方法是拉出你的layoutManager。例如

   private RecyclerView.OnScrollListener mListener = new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);

        GridLayoutManager layoutManager=GridLayoutManager.class.cast(recyclerView.getLayoutManager());
        int visibleItemCount = layoutManager.getChildCount();
        int totalItemCount = layoutManager.getItemCount();
        int pastVisibleItems = layoutManager.findFirstCompletelyVisibleItemPosition();

        if(pastVisibleItems+visibleItemCount >= totalItemCount){
            // End of the list is here.
            Log.i(TAG, "End of list");
        }
    }
}

希望它有所帮助!

答案 3 :(得分:1)

使用此代码避免重复通话

使用-1来检测顶部

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            if (!recyclerView.canScrollVertically(1) && newState==RecyclerView.SCROLL_STATE_IDLE) {
                Log.d("-----","end");

            }
        }
    });

答案 4 :(得分:1)

@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
   super.onScrollStateChanged(recyclerView, newState);
   if (!recyclerView.canScrollVertically(1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
              //reached end
   }

   if (!recyclerView.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
              //reached top
   }
   if(newState == RecyclerView.SCROLL_STATE_DRAGGING){
           //scrolling
   }
}

答案 5 :(得分:0)

此处是滚动停止后(对于RecyclerView)

执行操作的完整解决方案

已更正与recyclelerView滚动相关的异常OutOfBounds

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        //Your action here
                    }
                });

答案 6 :(得分:0)

我认为其他答案并不能解决您的痛点。

关于问题

正如您所说,RecycleView将在onScrolled()方法之前调用onScrollStateChanged()。但是,onScrollStateChanged()方法只能告诉您RecycleView的三种状态:

  • SCROLL_STATE_IDLE
  • SCROLL_STATE_DRAGGING
  • SCROLL_STATE_SETTLING

这意味着,假设RecycleView现在位于其顶部,如果用户向上滚动,则只能触发onScrollStateChanged()方法,而不能触发onScrolled()方法。 而且,如果用户向下滚动,则可以先触发onScrollStateChanged()方法,然后触发onScrolled()方法。

然后问题来了,SCROLL_STATE_DRAGGING只能告诉您用户在拖动视图,而不能告诉他拖动的方向。

您必须结合使用dy中的onScrolled()方法来检测拖动方向,但是onScrolled()不会被onScrollStateChanged()触发。

我的解决方案:

onScrollStateChanged()触发时记录滚动状态,然后延迟10毫秒之类的时间,检查是否有Y轴移动,并得出拖动方向的结论。

科林代码:

class DraggingDirectionScrollListener(private val view: View)
        : RecyclerView.OnScrollListener() {
        private val DIRECTION_NONE = -1
        private val DIRECTION_UP = 0
        private val DIRECTION_DOWN = 1

        var scrollDirection = DIRECTION_NONE
        var listStatus = RecyclerView.SCROLL_STATE_IDLE
        var totalDy = 0

        override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
            listStatus = newState

            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                scrollDirection = DIRECTION_NONE
            }

            if (isOnTop() && newState == RecyclerView.SCROLL_STATE_DRAGGING) {
              view.postDelayed({
                    if (getDragDirection() == DIRECTION_DOWN){
                        // Drag down from top
                    }else if (getDragDirection() == DIRECTION_UP) {
                        // Drag Up from top
                    }
                }, 10)
            }
        }

        override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
            this.totalDy += dy
            scrollDirection = when {
                dy > 0 -> DIRECTION_UP
                dy < 0 -> DIRECTION_DOWN
                else -> DIRECTION_NONE
            }

        }

        /**
         * is on the top of the list
         */
        private fun isOnTop():Boolean{
            return totalDy == 0
        }

        /**
         * detect dragging direction
         */
        private fun getDragDirection():Int {
            if (listStatus != RecyclerView.SCROLL_STATE_DRAGGING) {
                return DIRECTION_NONE
            }

            return when (scrollDirection) {
                DIRECTION_NONE -> if (totalDy == 0){
                    DIRECTION_DOWN  // drag down from top
                }else{
                    DIRECTION_UP  // drag up from bottom
                }
                DIRECTION_UP -> DIRECTION_UP
                DIRECTION_DOWN -> DIRECTION_DOWN
                else -> DIRECTION_NONE
            }
        }
    }

答案 7 :(得分:0)

您可以使用 RecyclerView.getScrollState() 来检测 RecyclerView.SCROLL_STATE_IDLE 或另一种状态。

我的情况:

if (recyclerView?.scrollState != RecyclerView.SCROLL_STATE_IDLE) {
    return
}