Comment faire défiler vers le bas D'un RecyclerView? scrollToPosition ne fonctionne pas
Je voudrais faire défiler vers le bas de la liste RecyclerView après le chargement de l'activité.
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 pour 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. Il y a 30 éléments dans GENERIC_MESSAGE_LIST
.
15 réponses
Juste ensemble setStackFromEnd=true
ou setReverseLayout=true
de sorte que LLM mettra en page les éléments de fin.
La différence entre ces deux est que setStackFromEnd
définira la vue pour afficher le dernier élément, la direction de mise en page restera la même. (Ainsi, dans une vue de recycleur horizontal de gauche à droite, le dernier élément sera affiché et le défilement vers la gauche affichera les éléments précédents)
Alors que {[4] } modifiera l'ordre des éléments ajoutés par L'Adaptateur. La mise en page commencera à partir de la dernière élément, qui sera le plus à gauche dans une vue LTR Recycler, puis, le défilement vers la droite montrera 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.
, je regardais ce post pour trouver la réponse, mais... Je pense que tout le monde sur ce post était confronté au même scénario que moi: scrollToPosition()
a été complètement ignoré, pour une raison évidente.
Ce que j'utilisais?
recyclerView.scrollToPosition(items.size());
... qu'est-ce que a fonctionné ?
recyclerView.scrollToPosition(items.size() - 1);
Je sais qu'il est tard pour répondre ici, encore si quelqu'un veut savoir que la solution est ci-dessous
conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);
Pour faire défiler de n'importe quelle position dans recyclerview 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 pose pas et ne positionne pas immédiatement les éléments sur l'écran (qui prend une seule passe de mise en page), d'où votre appel scrollToPosition()
n'a pas d'éléments réels à faire défiler lorsque vous l'appelez.
Au lieu de cela, vous devez enregistrer un ViewTreeObserver.OnGlobalLayoutListener (via addOnGlobalLayoutListner () à partir d'un ViewTreeObserver
Créé par conversationView.getViewTreeObserver()
) qui retarde votre scrollToPosition()
jusqu'après la première passe de 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.
}
});
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 pas lisse et pas cool.
Si vous avez un adaptateur attaché avec recyclerView, faites-le simplement.
mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());
La réponse Roc est d'une grande aide. Je voudrais y ajouter un petit bloc:
mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
Cela fonctionne parfaitement pour moi:
AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
Ajoutez ce code après l'envoi du message et avant de recevoir le message du serveur
recyclerView.scrollToPosition(mChatList.size() - 1);
Dans mon cas où les vues n'ont pas la même hauteur, en appelant scrollToPosition sur le LayoutManager travaillé pour vraiment faire défiler vers le bas et voir pleinement le dernier élément:
recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);
Seule la réponse de Ian a pu faire défiler mon RecyclerView
jusqu'à une position spécifiée. Cependant, le RecyclerView
n'a pas pu faire défiler après quand j'ai utilisé scrollToPosition()
. smoothScrollToPosition()
a fonctionné mais l'animation initiale l'a rendue trop lente lorsque la liste était longue.
La raison en était que l'auditeur n'a pas été supprimé. J'ai utilisé le code ci-dessous pour supprimer le ViewTreeObserver
et cela a fonctionné comme un charme.
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mRecyclerView.scrollToPosition(mPosition);
mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
Dans Kotlin:
recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }
private fun scrollToEnd() =
(adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)
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);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
layoutManager.setReverseLayout(true);// Scroll to bottom
recyclerView.setLayoutManager(layoutManager);