Android: smoothScrollToPosition () no funciona correctamente

Estoy tratando de desplazarse sin problemas hasta el último elemento de una lista después de agregar un elemento al arrayadapter asociado con el listview. El problema es que sólo 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); 

Es probable que desee decirle a ListView para publicar el desplazamiento cuando el hilo de la interfaz de usuario puede manejarlo (que es por qué el suyo no se desplaza correctamente). SmoothScroll necesita hacer mucho trabajo, en lugar de simplemente ir a una posición ignorando la velocidad / tiempo / etc. (Necesario para una "animación").

Por lo tanto usted debe hacer algo como:

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

(Copiado de mi respuesta: smoothScrollToPositionFromTop () no siempre funciona como debería )

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

Sin embargo, he implementado esta solución que se ocupa de todos los casos de borde que pueden producirse:

Primero llama a smothScrollToPositionFromTop(position) y luego, cuando el desplazamiento ha terminado, llama 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 animadamente hacia esta posición.

Implementé esta solución en dos métodos auxiliares:

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 utilizar 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 salta lo que quedaba. Otra solución es recordar el método repetidamente hasta que la primera posición visible sea su índice. Esto es mejor hacer rápidamente y con un límite ya que luchará el usuario desplazando la vista de lo contrario.

 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 traducir fácilmente a Java.

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

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

 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); 
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.