android listview selection android-arrayadapter smooth-scrolling

android: smoothScrollToPosition() no funciona correctamente



listview selection (6)

Estoy intentando desplazarme sin problemas al último elemento de una lista después de agregar un elemento al adaptador de arrays asociado con la vista de lista. El problema es que simplemente se desplaza a una posición aleatoria

arrayadapter.add(item); //DOES NOT WORK CORRECTLY: listview.smoothScrollToPosition(arrayadapter.getCount()-1); //WORKS JUST FINE: listview.setSelection(arrayadapter.getCount()-1);


¿ arrayadapter.notifyDataSetChanged() a arrayadapter.notifyDataSetChanged() después de llamar a arrayadapter.add() ? También para estar seguro, smoothScrollToPosition y setSelection son métodos disponibles en ListView no arrayadapter como lo mencionó anteriormente.

En cualquier caso, compruebe si esto ayuda: smoothScrollToPosition después de notifyDataSetChanged no funciona en Android


(Copiado de mi respuesta: .com/questions/14479078/… )

Este es un error conocido. Ver https://code.google.com/p/android/issues/detail?id=36062

Sin embargo, implementé esta solución que trata con todos los casos extremos que pueden ocurrir:

Primero llame a smothScrollToPositionFromTop(position) y luego, cuando el desplazamiento haya finalizado, llame a setSelection(position) . La última llamada corrige el desplazamiento incompleto saltando directamente a la posición deseada. Al hacerlo, el usuario todavía tiene la impresión de que se está desplazando por animación a esta posición.

Implementé esta solución dentro de dos métodos de ayuda:

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; } }


Debe usar el método setSelection ().


El método de selección de conjuntos mencionado por Lars funciona, pero la animación era demasiado nerviosa para nuestros propósitos, ya que omite lo que quedaba. Otra solución es recordar el método repetidamente hasta que la primera posición visible sea su índice. Esto se realiza mejor de forma rápida y con un límite, ya que de lo contrario luchará contra el usuario desplazándose por la vista.

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 solución está en C # vía. Xamarin pero debería traducirse fácilmente a Java.


Es probable que desee decirle al ListView que publique el desplazamiento cuando el subproceso de la interfaz de usuario pueda manejarlo (razón por la cual no se desplaza correctamente). SmoothScroll necesita hacer mucho trabajo, en lugar de simplemente ir a una posición que ignora la velocidad / tiempo / etc. (requerido para una "animación").

Por lo tanto, deberías hacer algo como:

getListView().post(new Runnable() { @Override public void run() { getListView().smoothScrollToPosition(pos); } });


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);