42 votes

Implémentation de onScrollListener pour détecter la fin du défilement dans un ListView

J'ai un ListView de l'affichage de certains éléments. J'aimerais effectuer une opération sur les éléments qui sont actuellement affichées dans la partie visible de l' ListView, selon la façon dont l' ListView a fait défiler; donc j'ai pensé à implémente l' OnScrollListener de la ListView. En conséquence, pour le Android de référence de l'api, le onScroll méthode "sera appelé après le défilement est terminé". Cela me semble être juste ce dont j'avais besoin, car une fois le défilement est terminé, j'ai effectuer mes actions sur l' ListView (le onScroll méthode renvoie l'index du premier élément affiché et le nombre d'éléments affichés).

Mais une fois mis en place, je vois de l' LogCat que le onScroll méthode n'est pas juste mis le feu une fois que le défilement est terminé, mais est déclenché pour chaque nouvel élément qui entre dans l'affichage de la vue, du début à la fin de la vitesse de défilement. Ce n'est pas le comportement que j'attends, ni j'ai besoin. L'autre méthode de l'auditeur (onScrollStateChanged), au lieu de cela, ne fournissent pas d'informations sur les éléments affichés dans la ListView.

Donc, est-ce que quelqu'un sait comment utiliser ce couple de méthodes pour détecter la fin du défilement et d'obtenir les informations sur les éléments affichés? Le décalage entre la référence de l'api et le comportement réel de la méthode qui me confond un peu. Merci à l'avance.

P. S.: j'ai vu quelques-uns des sujets similaires autour, mais rien ne me permet de comprendre comment le tout fonctionne..!

54voto

e-cal Points 823

En fin de compte j'en suis arrivé à une solution pas tellement élégant, mais qui a fonctionné pour moi; ayant compris que onScroll méthode est appelée à chaque étape de la vitesse de défilement au lieu de simplement être appelé à le faire défiler la fin, et que onScrollStateChanged est appelée que lorsque le défilement est terminé, je fais quelque chose comme ceci:

public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    this.currentFirstVisibleItem = firstVisibleItem;
    this.currentVisibleItemCount = visibleItemCount;
}

public void onScrollStateChanged(AbsListView view, int scrollState) {
    this.currentScrollState = scrollState;
    this.isScrollCompleted();
 }

private void isScrollCompleted() {
    if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) {
        /*** In this way I detect if there's been a scroll which has completed ***/
        /*** do the work! ***/
    }
}

Pratiquement, chaque fois que la liste est en cours de défilement-je sauvegarder les données sur le premier élément visible et le visible de l'élément de comptage (onScroll méthode); lorsque l'état de défilement des changements (onScrollStateChanged) - je économiser de l'état et j'en appelle une autre méthode qui, en fait, de comprendre si il y a eu un parchemin et si c'est terminé. De cette façon, j'ai aussi les données sur les articles dont j'ai besoin. Peut-être pas propre, mais ça fonctionne!

Ce qui concerne

13voto

Lunatikul Points 195
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {

if (list.getLastVisiblePosition() == list.getAdapter().getCount() - 1
&& list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) {
//scroll end reached
//Write your code here
}
}

9voto

trytrysee Points 21
@Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {

            if((firstVisibleItem + visibleItemCount) ==  totalItemCount)
            {
                Log.i("Info", "Scroll Bottom" );
            }
        }});

6voto

dmon Points 20795

Pour obtenir ce comportement est en bas, délicate, et m'a fallu un certain temps pour se perfectionner. La viande du problème, c'est que le défilement des auditeurs par eux-mêmes ne sont pas vraiment tout à fait suffisant pour détecter un "arrêt stop" (y compris les touches directionnelles/boule de commande), aussi loin que je pouvais dire. J'ai fini par faire une combinaison de choses qui travaille juste que je l'attends.

La meilleure façon que j'ai pensé que je pouvais faire c'était de prolonger ListView et remplacer quelques méthodes:

  ....
  @Override
  public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) {
      startWait();
    }
    return super.onKeyUp(keyCode, event);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
      stopWait();
    }
    if (event.getAction() == MotionEvent.ACTION_UP ||
        event.getAction() == MotionEvent.ACTION_CANCEL) {
      startWait();
    }
    return super.onTouchEvent(event);
  }

  private OnScrollListener customScrollListener = new OnScrollListener() {
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
      int totalItemCount) {
      stopWait();
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
      if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
        startWait();
      } else {
        stopWait();
      }
    }
  };

  //All this waiting could be improved, but that's the idea
  private Thread waitThread = null;
  private int waitCount  = Integer.MIN_VALUE;

  public void stopWait() {
    waitCount = Integer.MIN_VALUE;
  }

  public synchronized void startWait() {
    waitCount = 0;

    if (waitThread != null) {
      return;
    }

    waitThread = new Thread(new Runnable() {
    @Override
    public void run() {
    try {
      for (; waitCount.get() < 10; waitCount++) {
        Thread.sleep(50);
      }

        //Kick it back to the UI thread.
        view.post(theRunnableWithYourOnScrollStopCode); // HERE IS WHERE YOU DO WHATEVER YOU WANTED TO DO ON STOP
      } catch (InterruptedException e) {
      } finally  {
        waitThread = null;
      }
    }
  });
  waitThread.start();
}

Notez que vous avez également de lier l' customScrollListener de votre constructeur. Cette mise en œuvre est bien, je crois, car il ne sera pas immédiatement le feu "l'événement", il faudra patienter un peu jusqu'à ce qu'il a fait complètement arrêté de défiler.

0voto

Ajith Memana Points 664

Il existe encore une solution simple. Mettez un auditeur dans l'adaptateur de listview et dans getview vérifiez si (position == totalItemCount du nombre d'éléments dans un tableau à afficher), si oui, j'appelle mon écouteur depuis l'adaptateur et dans l'écouteur. Exécutez votre opération, quelle qu'elle soit

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X