web-dev-qa-db-fra.com

Comment faire défiler vers le bas d'un RecyclerView? scrollToPosition ne fonctionne pas

Après avoir chargé l'activité, j'aimerais aller au bas de la liste RecyclerView.

GENERIC_MESSAGE_LIST = (ArrayList) intent.getExtras().getParcelableArrayList(ConversationsAdapter.EXTRA_MESSAGE);
conversationView = (RecyclerView) findViewById(R.id.list_messages);
conversationView.setHasFixedSize(true);
conversationViewLayoutManager = new LinearLayoutManager(this);
conversationView.setLayoutManager(conversationViewLayoutManager);
conversationViewAdapter = new ConversationAdapter(GENERIC_MESSAGE_LIST, this);
conversationView.setAdapter(conversationViewAdapter);

conversationView.scrollTo(...) lève une exception sur le fait de ne pas être pris en charge dans RecyclerView et conversationView.scrollToPosition(...) ne semble rien faire.

Après le bloc de code ci-dessus, j'ai ajouté

conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)

qui ne fonctionne pas. GENERIC_MESSAGE_LIST contient 30 éléments.

118
waylaidwanderer

Il suffit de définir setStackFromEnd=true ou setReverseLayout=true pour que LLM organise les éléments à partir de la fin.

La différence entre ces deux éléments est que setStackFromEnd définira la vue pour afficher le dernier élément, la direction de la présentation demeurant la même. (Ainsi, dans une vue horizontale du recycleur de gauche à droite, le dernier élément sera affiché et un défilement vers la gauche affichera les éléments précédents)

Tandis que setReverseLayout changera l'ordre des éléments ajoutés par l'adaptateur. La mise en page commencera à partir du dernier élément, qui sera l'élément le plus à gauche dans une vue LTR Recycler, puis un défilement vers la droite affichera les éléments précédents.

Échantillon:

final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);

Voir documentation pour plus de détails.

167
yigit

Je regardais ce billet pour trouver la réponse, mais ... Je pense que tout le monde était confronté au même scénario que moi: scrollToPosition() a été totalement ignoré, pour une raison évidente.

Qu'est-ce que j'utilisais?

recyclerView.scrollToPosition(items.size());

... Qu'est-ce queA TRAVAILLÉ?

recyclerView.scrollToPosition(items.size() - 1);
292
Roc Boronat

Je sais qu'il est tard pour répondre ici, encore si quelqu'un veut savoir la solution est ci-dessous

conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);
43
WritingForAnroid

Pour faire défiler une position quelconque de la vue d'ensemble vers le bas

edittext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv_commentList.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      rv_commentList.scrollToPosition(rv_commentList.getAdapter().getItemCount() - 1);
                    }
                }, 1000);
            }
        });

Lorsque vous appelez setAdapter, cela ne met pas immédiatement en place et ne positionne pas les éléments à l'écran (cela prend une seule passe de présentation), votre appel scrollToPosition() ne contient donc aucun élément réel à faire défiler lorsque vous l'appelez.

Au lieu de cela, vous devez enregistrer un ViewTreeObserver.OnGlobalLayoutListener (via addOnGlobalLayoutListner () à partir d'une ViewTreeObserver créée par conversationView.getViewTreeObserver()) qui retarde votre scrollToPosition() jusqu'à la fin de la première mise en page:

conversationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  public void onGlobalLayout() {
    conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size();
    // Unregister the listener to only call scrollToPosition once
    conversationView.getViewTreeObserver().removeGlobalOnLayoutListener(this);

    // Use vto.removeOnGlobalLayoutListener(this) on API16+ devices as 
    // removeGlobalOnLayoutListener is deprecated.
    // They do the same thing, just a rename so your choice.
  }
});
8
ianhanniballake

Ajoutez ce code après l'envoi du message et avant de recevoir le message du serveur

recyclerView.scrollToPosition(mChatList.size() - 1);
7
Shubham Agrawal
class MyLayoutManager extends LinearLayoutManager {

  public MyLayoutManager(Context context) {
    super(context, LinearLayoutManager.VERTICAL, false);
  }

  @Override public void smoothScrollToPosition(RecyclerView recyclerView,
      final RecyclerView.State state, final int position) {

    int fcvip = findFirstCompletelyVisibleItemPosition();
    int lcvip = findLastCompletelyVisibleItemPosition();

    if (position < fcvip || lcvip < position) {
      // scrolling to invisible position

      float fcviY = findViewByPosition(fcvip).getY();
      float lcviY = findViewByPosition(lcvip).getY();

      recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {

        int currentState = RecyclerView.SCROLL_STATE_IDLE;

        @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

          if (currentState == RecyclerView.SCROLL_STATE_SETTLING
              && newState == RecyclerView.SCROLL_STATE_IDLE) {

            // recursive scrolling
            smoothScrollToPosition(recyclerView, state, position);
          }

          currentState = newState;
        }

        @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

          int fcvip = findFirstCompletelyVisibleItemPosition();
          int lcvip = findLastCompletelyVisibleItemPosition();

          if ((dy < 0 && fcvip == position) || (dy > 0 && lcvip == position)) {
            // stop scrolling
            recyclerView.setOnScrollListener(null);
          }
        }
      });

      if (position < fcvip) {
        // scroll up

        recyclerView.smoothScrollBy(0, (int) (fcviY - lcviY));
      } else {
        // scroll down

        recyclerView.smoothScrollBy(0, (int) (lcviY - fcviY));
      }
    } else {
      // scrolling to visible position

      float fromY = findViewByPosition(fcvip).getY();
      float targetY = findViewByPosition(position).getY();

      recyclerView.smoothScrollBy(0, (int) (targetY - fromY));
    }
  }
}

et

MyLayoutManager layoutManager = new MyLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);

RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);

recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);

le code ci-dessus fonctionne, mais ce n’est ni lisse ni cool.

4
Yuki Yoshida

Solution pour Kotlin :

appliquer le code ci-dessous après avoir défini "recyclerView.adapter" ou après "recyclerView.adapter.notifyDataSetChanged ()"

recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)
4
chinnuabhi

Dans mon cas, où les vues n’ont pas la même hauteur, appeler scrollToPosition sur le LayoutManager s’efforce de faire défiler le fond de la page et de voir le dernier élément:

recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);
3
galex

Roc answer est d'une grande aide. Je voudrais y ajouter un petit bloc:

mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
3
abedfar

Cela fonctionne parfaitement bien pour moi:

AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
2
amaresh hiremani

À Kotlin:

recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }

private fun scrollToEnd() =
        (adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)
1
yanchenko

Essayé une méthode de @ galex , cela a fonctionné jusqu'au refactoring. J'ai donc utilisé une réponse de @ yanchenko et changé un peu. C'est probablement parce que j'ai appelé scrolling from onCreateView(), où une vue fragmentée a été construite (et n'avait probablement pas la bonne taille).

private fun scrollPhotosToEnd(view: View) {
    view.recycler_view.viewTreeObserver.addOnGlobalLayoutListener(object :
        ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                view.recycler_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
            } else {
                @Suppress("DEPRECATION")
                view.recycler_view.viewTreeObserver.removeGlobalOnLayoutListener(this)
            }
            adapter?.itemCount?.takeIf { it > 0 }?.let {
                view.recycler_view.scrollToPosition(it - 1)
            }
        }
    })
}

Vous pouvez également ajouter une vérification de viewTreeObserver.isAlive comme dans https://stackoverflow.com/a/39001731/291414 .

0
CoolMind

ce code vous donnera le dernier message en premier, je pense que cette réponse est utile. 

    mInstaList=(RecyclerView)findViewById(R.id.insta_list);
    mInstaList.setHasFixedSize(true);

    LinearLayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

    mInstaList.setLayoutManager(layoutManager);
    layoutManager.setStackFromEnd(true);
    layoutManager.setReverseLayout(true);
0
hasanga lakdinu

Seule la réponse de Ian a pu faire défiler ma RecyclerView à une position spécifiée. Cependant, la RecyclerView n'a pas pu défiler après l'utilisation de scrollToPosition(). smoothScrollToPosition() a fonctionné, mais l'animation initiale l'a ralentie lorsque la liste était longue. La raison en était que l'auditeur n'a pas été retiré. J'ai utilisé le code ci-dessous pour supprimer la ViewTreeObserver actuelle et cela a fonctionné comme un charme.

    mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mRecyclerView.scrollToPosition(mPosition);
            mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });
0
Anky An

Faites défiler pour la première fois lors de la première utilisation de la vue Recycler, puis utilisez linearLayoutManager.scrollToPositionWithOffset (messageHashMap.size () - 1, mis moins pour faire défiler vers le haut pour faire défiler vers le haut, mettez une valeur positive);

si la vue est très grande en hauteur, alors offset est utilisé pour le dessus de la vue puis vous utilisez

int globalXScroldl = chatMessageBinding.rvChat.computeVerticalScrollOffset (); chatMessageBinding.rvChat.smoothScrollBy (0, Math.abs ( OverallXScroldl));;

0
Dishant Kawatra