Обнаружение начала прокрутки и завершения прокрутки в режиме recyclerview
Мне нужно определить начало/конец и направление прокрутки в режиме recyclerview. У слушателя прокрутки есть два метода: onScrolled()
и onScrollStateChanged()
. Первый метод вызывается после запуска свитка (на самом деле он называется onScrolled(), а не onScrolling()). Второй способ дает информацию о состоянии, но у меня нет информации о направлении. Как я могу достичь своей цели?
Ответы
Ответ 1
шаг 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");
}
}
}
step 2- Поскольку setOnScrollListener устарел, лучше использовать addOnScrollListener
mRecyclerView.addOnScrollListener(new CustomScrollListener());
Ответ 2
Смотрите документацию для 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;
}
Ответ 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");
}
}
}
Надеюсь, это поможет!
Ответ 4
здесь представлено полное решение для выполнения действия после остановки прокрутки (для RecyclerView)
который исправил мой Exception OutOfBounds, связанный с прокруткой recyclerView
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
//Your action here
}
});
Ответ 5
Я думаю, что другие ответы не касаются вашей боли.
О вопросе
Как вы сказали, RecycleView вызовет onScrollStateChanged() перед методом onScrolled(). Однако метод onScrollStateChanged() может сообщить вам только три состояния RecycleView:
- SCROLL_STATE_IDLE
- SCROLL_STATE_DRAGGING
- SCROLL_STATE_SETTLING
Это означает, что предположим, что RecycleView сейчас на вершине, если пользователь прокручивает вверх, он может запускать onScrollStateChanged()
метод onScrollStateChanged()
, но не onScrolled()
. И если пользователь прокручивает onScrollStateChanged()
вниз, он может onScrollStateChanged()
вызвать onScrollStateChanged()
, а затем onScrolled()
.
Тогда возникает проблема, SCROLL_STATE_DRAGGING
может только сказать вам, что пользователь перетаскивает представление, а не SCROLL_STATE_DRAGGING
направление его перетаскивания.
Вы должны комбинировать с методом dy
из onScrolled()
чтобы определить направление перетаскивания, но onScrolled()
не запускается с onScrollStateChanged()
.
MySolution:
Запишите состояние прокрутки при 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
}
}
}
Ответ 6
Используйте этот код для избежания повторных звонков
используйте -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");
}
}
});