Android 在recyclerview中检测开始滚动和结束滚动
我需要在recyclerview中检测滚动的开始/结束和方向。滚动侦听器有两种方法:Android 在recyclerview中检测开始滚动和结束滚动,android,android-recyclerview,Android,Android Recyclerview,我需要在recyclerview中检测滚动的开始/结束和方向。滚动侦听器有两种方法:onscroll()和onScrollStateChanged()。第一个方法在滚动启动后调用(实际上称为onscroll(),而不是onScrolling())。第二种方法提供了关于状态的信息,但我没有方向信息。如何实现我的目标?有关详细信息,请参阅文档。 三个可能的值是: SCROLL\u STATE\u IDLE:不进行滚动 SCROLL\u STATE\u drawing:用户在屏幕上拖动手指(或按编程
onscroll()
和onScrollStateChanged()
。第一个方法在滚动启动后调用(实际上称为onscroll(),而不是onScrolling())。第二种方法提供了关于状态的信息,但我没有方向信息。如何实现我的目标?有关详细信息,请参阅文档。
三个可能的值是:
:不进行滚动SCROLL\u STATE\u IDLE
:用户在屏幕上拖动手指(或按编程方式进行)SCROLL\u STATE\u drawing
:用户已抬起手指,动画现在变慢SCROLL\u STATE\u setting
public void onScrollStateChanged(int state) {
boolean hasStarted = state == SCROLL_STATE_DRAGGING;
boolean hasEnded = state == SCROLL_STATE_IDLE;
}
步骤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");
}
}
}
最简单的方法是退出你的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");
}
}
}
希望有帮助!这里有一个完整的解决方案,可以在停止滚动后执行操作(用于RecyclerView) 这已经纠正了我与recyclerView滚动相关的OutOfBounds异常
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
//Your action here
}
});
我认为其他答案没有触及你的痛处 关于这个问题 正如您所说,RecycleView将在OnScroll()方法之前调用onScrollStateChanged()。但是,onScrollStateChanged()方法只能告诉您RecycleView的三种状态:
- 滚动\u状态\u空闲
- 滚动\u状态\u拖动
- 滚动\u状态\u设置
onScrollStateChanged()
方法,而不能触发onScrolled()
方法。
如果用户向下滚动,它可以首先触发onScrollStateChanged()
方法,然后触发onScrolled()
方法
然后问题就来了,SCROLL\u STATE\u drawing
只能告诉您用户正在拖动视图,而不能告诉他拖动的方向
您必须结合onScrolled()
方法中的dy
来检测拖动方向,但是onScrolled()
不会触发onScrollStateChanged()
我的解决方案:
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
}
}
}
当触发onScrollStateChanged()
时,记录滚动状态,然后删除一段时间,如10ms,检查是否有Y轴移动,并得出拖动方向的结论
Kotlin代码:
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
}
}
}
class DraggingDirectionScrollListener(私有val视图:视图)
:RecyclerView.OnScrollListener(){
私有值方向_NONE=-1
专用val方向_向上=0
专用val方向_向下=1
var scrollDirection=方向\u无
var listStatus=RecyclerView.SCROLL\u STATE\u IDLE
var totalDy=0
覆盖CrollStateChanged(recyclerView:recyclerView?,newState:Int){
listStatus=newState
if(newState==RecyclerView.SCROLL\u STATE\u IDLE){
滚动方向=方向\无
}
if(isOnTop()&&newState==RecyclerView.SCROLL\u STATE\u drawing){
view.postdayed({
如果(getDragDirection()==方向\u向下){
//从顶部向下拖动
}else if(getDragDirection()==向上的方向){
//从顶部向上拖动
}
}, 10)
}
}
覆盖已克隆的乐趣(recyclerView:recyclerView?,dx:Int,dy:Int){
this.totalDy+=dy
滚动方向=何时{
dy>0->向上方向
dy<0->向下的方向
其他->方向\u无
}
}
/**
*在列表的顶部
*/
private fun isOnTop():布尔值{
返回totalDy==0
}
/**
*检测拖动方向
*/
private fun getDragDirection():Int{
如果(listStatus!=RecyclerView.SCROLL\u STATE\u Draging){
返回方向\u无
}
返回时间(滚动方向){
方向\u无->如果(totalDy==0){
方向\向下//从顶部向下拖动
}否则{
方向_向上//从底部向上拖动
}
方向向上->方向向上
方向向下->方向向下
其他->方向\u无
}
}
}
使用此代码避免重复呼叫
使用-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");
}
}
});
您可以使用
RecyclerView.getScrollState()
来检测RecyclerView.SCROLL\u STATE\u IDLE
或另一种状态
我的情况是:
if (recyclerView?.scrollState != RecyclerView.SCROLL_STATE_IDLE) {
return
}
好的,但是怎么能同时检测到方向呢?你可以覆盖
onScrolled(intdx,intdy)
并检查dy
是否为正或负,这为您提供了一个或另一个方向。RecyclerView.OnScrollListener
不是一个界面/facepalm@google开发人员决定的。在这种情况下,我更喜欢一个类,因为您不需要重写这两个方法。此方法已被弃用,无法在上述v中工作可能是23版或M版,但评论来自2018年,我只是通知您用当前场景更新您的答案。
if (recyclerView?.scrollState != RecyclerView.SCROLL_STATE_IDLE) {
return
}