web-dev-qa-db-fra.com

Existe-t-il un rappel lorsque RecyclerView a fini de montrer ses éléments après que je l'ai configuré avec un adaptateur?

Contexte

J'ai créé une bibliothèque qui montre un défilement rapide pour RecyclerView ( ici , au cas où quelqu'un le voudrait), et je voulez décider quand montrer et quand cacher le défilement rapide.

Je pense qu'une bonne décision serait que s'il y a des éléments qui ne sont pas affichés à l'écran (ou s'il y en a beaucoup qui n'apparaissent pas), une fois que RecyclerView a terminé son processus de mise en page, je définirais le défilement rapide sur être visible, et si tous les éléments sont déjà affichés, il n'est pas nécessaire de le montrer.

Le problème

Je ne trouve pas d'écouteur/de rappel pour le RecyclerView, pour me dire quand il a fini d'afficher les éléments, afin que je puisse vérifier le nombre d'éléments affichés par rapport au nombre d'éléments.

Le recyclerView peut également changer sa taille lorsque le clavier apparaît et se cache.

Ce que j'ai essayé

L'auditeur de défilement ne sera probablement pas utile, car il se produit "tout le temps", et je n'ai besoin de vérifier que lorsque RecyclerView a changé de taille ou lorsque le nombre d'éléments (ou les données) a changé.

Je pourrais envelopper le RecyclerView avec une disposition qui m'informe des changements de taille, comme celui-ci que j'ai fait, mais je ne pense pas que cela fonctionnera car le RecyclerView ne sera probablement pas encore prêt pour dire combien d'éléments sont visibles.

La façon de vérifier le nombre d'éléments affichés peut être utilisée comme telle:

    final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
    mRecyclerView.setLayoutManager(layoutManager);
    ...
    Log.d("AppLog", "visible items count:" + (layoutManager.findLastVisibleItemPosition() -layoutManager.findFirstVisibleItemPosition()+1));

La question

Comment puis-je être averti lorsque le recyclerView a fini de montrer ses vues enfant, afin que je puisse décider, en fonction de ce qui est actuellement affiché, d'afficher/masquer le défilement rapide?

40
android developer

J'ai trouvé un moyen de résoudre ce problème (grâce à l'utilisateur pskink ), en utilisant le rappel de LayoutManager:

final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
            @Override
            public void onLayoutChildren(final Recycler recycler, final State state) {
                super.onLayoutChildren(recycler, state);
                //TODO if the items are filtered, considered hiding the fast scroller here
                final int firstVisibleItemPosition = findFirstVisibleItemPosition();
                if (firstVisibleItemPosition != 0) {
                    // this avoids trying to handle un-needed calls
                    if (firstVisibleItemPosition == -1)
                        //not initialized, or no items shown, so hide fast-scroller
                        mFastScroller.setVisibility(View.GONE);
                    return;
                }
                final int lastVisibleItemPosition = findLastVisibleItemPosition();
                int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
                //if all items are shown, hide the fast-scroller
                mFastScroller.setVisibility(mAdapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
            }
        };

La bonne chose ici est qu'il fonctionne bien et gérera même le clavier affiché/caché.

La mauvaise chose est qu'il est appelé sur des cas qui ne sont pas intéressants (ce qui signifie qu'il a de faux positifs), mais ce n'est pas aussi souvent que les événements de défilement, donc c'est assez bon pour moi.


EDIT: il y a un meilleur rappel qui a été ajouté plus tard, qui n'est pas appelé plusieurs fois. Voici le nouveau code au lieu de ce que j'ai écrit ci-dessus:

        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
            @Override
            public void onLayoutCompleted(final State state) {
                super.onLayoutCompleted(state);
                final int firstVisibleItemPosition = findFirstVisibleItemPosition();
                final int lastVisibleItemPosition = findLastVisibleItemPosition();
                int itemsShown = lastVisibleItemPosition - firstVisibleItemPosition + 1;
                //if all items are shown, hide the fast-scroller
                fastScroller.setVisibility(adapter.getItemCount() > itemsShown ? View.VISIBLE : View.GONE);
            }
        });
26
android developer

J'utilise 'addOnGlobalLayoutListener' pour cela. Voici mon exemple:

Définition d'une interface pour effectuer l'action requise après le chargement:

public interface RecyclerViewReadyCallback {
  void onLayoutReady();
}

sur RecyclerView, je déclenche la méthode onLayoutReady lorsque la charge est prête:

mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
  if (recyclerViewReadyCallback != null) {
    recyclerViewReadyCallback.onLayoutReady();
  }
  recyclerViewReadyCallback = null;
});

Remarque: la valeur null est nécessaire pour empêcher la méthode d'être appelée plusieurs fois.

0
Peter