smoothScrollToPositionFromTop () no siempre funciona como debería

He intentado por un tiempo hacer funcionar smoothScrollToPositionFromTop (), pero no siempre se desplaza a la posición correcta.

Tengo un ListView (con 10 elementos) en un diseño con 10 botones en el lateral, por lo que puedo desplazarme a cada elemento de la lista. Por lo general, cuando desplazo una posición hacia atrás o adelante, funciona bien, pero a menudo, cuando bash desplazar más de 3 posiciones hacia atrás o hacia delante, ListView no termina exactamente en la posición seleccionada. Cuando falla, generalmente termina con 0,5 a 1,5 elementos desactivados y no es realmente predecible cuando falla el desplazamiento.

También he comprobado que smoothScrollToPosition después de notifyDataSetChanged no funciona en Android , pero esta solución no funciona para mí y no cambio ningún dato.

Realmente me gustaría desplazarme automáticamente a los elementos de lista seleccionados, pero no puedo entender cómo. Alguien ha tenido este problema antes y sabe cómo solucionarlo?

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:

smoothScrollToPositionFromTop ()

 public static void smoothScrollToPositionFromTop(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; } } 

Aquí hay una implementación de la solución.

  void smoothScrollToPositionFromTopWithBugWorkAround(final AbsListView listView, final int position, final int offset, final int duration){ //the bug workaround involves listening to when it has finished scrolling, and then //firing a new scroll to the same position. //the bug is the case that sometimes smooth Scroll To Position sort of misses its intended position. //more info here : https://code.google.com/p/android/issues/detail?id=36062 listView.smoothScrollToPositionFromTop(position, offset, duration); listView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if(scrollState==OnScrollListener.SCROLL_STATE_IDLE){ listView.setOnScrollListener(null); listView.smoothScrollToPositionFromTop(position, offset, duration); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); }