我需要在recyclerview中检测滚动的开始/结束和方向。滚动侦听器有两种方法:onScrolled()
和onScrollStateChanged()
。滚动开始后调用第一个方法(实际上是调用onScrolled()而不是onScrolling())。第二种方法提供有关州的信息,但我没有方向信息。我怎样才能实现目标?
答案 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的三种状态:
这意味着,假设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
}