J'essaie de faire défiler en douceur vers le dernier élément d'une liste après avoir ajouté un élément à l'adaptateur de tableau associé à la vue de liste. Le problème est qu'il défile simplement vers une position aléatoire
arrayadapter.add(item);
//DOES NOT WORK CORRECTLY:
listview.smoothScrollToPosition(arrayadapter.getCount()-1);
//WORKS JUST FINE:
listview.setSelection(arrayadapter.getCount()-1);
Vous voudrez probablement dire à ListView de publier le défilement lorsque le thread d'interface utilisateur peut le gérer (c'est pourquoi le vôtre ne défile pas correctement). SmoothScroll a besoin de faire beaucoup de travail, au lieu d'aller simplement à une position ignorant la vitesse/le temps/etc. (requis pour une "animation").
Par conséquent, vous devez faire quelque chose comme:
getListView().post(new Runnable() {
@Override
public void run() {
getListView().smoothScrollToPosition(pos);
}
});
(Copié de ma réponse: smoothScrollToPositionFromTop () ne fonctionne pas toujours comme il se doit )
Il s'agit d'un bogue connu. Voir https://code.google.com/p/Android/issues/detail?id=36062
Cependant, j'ai implémenté cette solution de contournement qui traite de tous les cas Edge qui peuvent se produire:
Appelez d'abord smothScrollToPositionFromTop(position)
puis, lorsque le défilement est terminé, appelez setSelection(position)
. Ce dernier appel corrige le défilement incomplet en sautant directement à la position souhaitée. Ce faisant, l'utilisateur a toujours l'impression qu'il fait défiler l'animation vers cette position.
J'ai implémenté cette solution de contournement dans deux méthodes d'assistance:
smoothScrollToPosition ()
public static void smoothScrollToPosition(final AbsListView view, final int position) {
View child = getChildAtPosition(view, position);
// There's no need to scroll if child is already at top or view is already scrolled to its end
if ((child != null) && ((child.getTop() == 0) || ((child.getTop() > 0) && !view.canScrollVertically(1)))) {
return;
}
view.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
view.setOnScrollListener(null);
// Fix for scrolling bug
new Handler().post(new Runnable() {
@Override
public void run() {
view.setSelection(position);
}
});
}
}
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
final int totalItemCount) { }
});
// Perform scrolling to position
new Handler().post(new Runnable() {
@Override
public void run() {
view.smoothScrollToPositionFromTop(position, 0);
}
});
}
getChildAtPosition ()
public static View getChildAtPosition(final AdapterView view, final int position) {
final int index = position - view.getFirstVisiblePosition();
if ((index >= 0) && (index < view.getChildCount())) {
return view.getChildAt(index);
} else {
return null;
}
}
Vous devez utiliser la méthode setSelection ().
La méthode de sélection des ensembles mentionnée par Lars fonctionne, mais l'animation était trop nerveuse pour nous car elle saute tout ce qui reste. Une autre solution consiste à rappeler la méthode à plusieurs reprises jusqu'à ce que la première position visible soit votre index. Il est préférable de le faire rapidement et avec une limite car cela combattra l'utilisateur en faisant défiler la vue autrement.
private void DeterminedScrollTo(Android.Widget.ListView listView, int index, int attempts = 0) {
if (listView.FirstVisiblePosition != index && attempts < 10) {
attempts++;
listView.SmoothScrollToPositionFromTop (index, 1, 100);
listView.PostDelayed (() => {
DeterminedScrollTo (listView, index, attempts);
}, 100);
}
}
La solution est en C # via. Xamarin mais devrait se traduire facilement en Java.
Utilisez LayoutManager pour lisser le défilement
layoutManager.smoothScrollToPosition(recyclerView, new RecyclerView.State(), position);
final Handler handler = new Handler();
//100ms wait to scroll to item after applying changes
handler.postDelayed(new Runnable() {
@Override
public void run() {
listView.smoothScrollToPosition(selectedPosition);
}}, 100);
Appelez-vous arrayadapter.notifyDataSetChanged()
après avoir appelé arrayadapter.add()
? Pour être sûr aussi, smoothScrollToPosition
et setSelection
sont des méthodes disponibles dans ListView
pas arrayadapter
comme vous l'avez mentionné ci-dessus.
Dans tous les cas, voyez si cela aide: smoothScrollToPosition après notifyDataSetChanged ne fonctionne pas sur Android