Detect start scroll en end scroll in recyclerview

Ik moet het begin/einde en de richting van scrollen detecteren in een recyclerview. De scroll-listener heeft twee methoden: onScrolled()en onScrollStateChanged(). De eerste methode wordt aangeroepen nadat het scrollen is gestart (het heet inderdaad onScrolled() en niet onScrolling()). De tweede methode geeft informatie over de staat, maar ik heb geen richtingsinformatie. Hoe kan ik mijn doel bereiken?


Antwoord 1, autoriteit 100%

stap 1 U kunt een klasse maken die RecyclerView.OnScrollListener uitbreidt en deze methoden overschrijven

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

stap 2- Aangezien setOnScrollListener verouderd is, is het beter om addOnScrollListener te gebruiken

mRecyclerView.addOnScrollListener(new CustomScrollListener());

Antwoord 2, autoriteit 40%

Zie de documentatie voor onScrollStateChanged(int state).
De drie mogelijke waarden zijn:

  • SCROLL_STATE_IDLE: er wordt niet gescrolld.
  • SCROLL_STATE_DRAGGING: de gebruiker sleept zijn vinger over het scherm (of het wordt programmatisch gedaan.
  • SCROLL_STATE_SETTLING: gebruiker heeft zijn vinger opgetild en de animatie wordt nu langzamer.

Dus als je wilt detecteren wanneer het scrollen begint en eindigt, dan kun je zoiets als dit maken:

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

Antwoord 3, autoriteit 5%

Gebruik deze code om herhaalde oproepen te vermijden

gebruik -1 voor het detecteren van top

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

Antwoord 4, autoriteit 3%

De eenvoudigste manier om dit te doen, is door uw layoutManager tevoorschijn te halen. Bijvoorbeeld

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

Hopelijk helpt het!


Antwoord 5, autoriteit 2%

@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
   }
}

Antwoord 6

Ik denk dat de andere antwoorden je pijnpunt niet raken.

Over de vraag

Zoals je zei, zal RecycleView de onScrollStateChanged() aanroepen voor de onScrolled() methode. De methode onScrollStateChanged() kan u echter alleen de drie statussen van RecycleView vertellen:

  • SCROLL_STATE_IDLE
  • SCROLL_STATE_DRAGGING
  • SCROLL_STATE_SETTLING

Dat betekent, neem aan dat de RecycleView nu bovenaan staat, als de gebruiker omhoog scrolt, kan deze alleen de onScrollStateChanged()-methode activeren, maar niet de onScrolled()-methode .
En als de gebruiker naar beneden scrolt, kan het eerst de onScrollStateChanged()-methode activeren en vervolgens de onScrolled()-methode.

Dan komt het probleem, SCROLL_STATE_DRAGGINGkan je alleen vertellen dat de gebruiker de weergave sleept, niet de richting van zijn slepen.

Je moet combineren met de dyfrom onScrolled()methode om de sleeprichting te detecteren, maar onScrolled()wordt niet getriggerd met onScrollStateChanged().

Mijn Oplossing:

Neem de scrollstatus op wanneer onScrollStateChanged()werd geactiveerd, stel vervolgens een tijd uit, bijvoorbeeld 10 ms, controleer of er een beweging op de Y-as is en maak een conclusie over de sleeprichting.

Kotlin-code:

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

Antwoord 7

U kunt RecyclerView.getScrollState()gebruiken voor het detecteren van RecyclerView.SCROLL_STATE_IDLEof een andere staat.

Mijn zaak:

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

Antwoord 8

hier is een complete oplossing om een ​​actie uit te voeren nadat het scrollen is gestopt (voor RecyclerView)

die mijn Exception OutOfBounds met betrekking tot het scrollen van recyclerView heeft gecorrigeerd

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

Other episodes