42

Estoy intentando desplazarme sin problemas al último elemento de una lista después de agregar un elemento al arrayadapter asociado con la vista de lista. El problema es que simplemente se desplaza a una posición aleatoriaandroid: smoothScrollToPosition() no funciona correctamente

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

//WORKS JUST FINE: 
listview.setSelection(arrayadapter.getCount()-1); 
+1

y este método nunca funcionó para mí. –

+2

Error conocido: ver respuesta https://stackoverflow.com/questions/14479078/smoothscrolltopositionfromtop-is-not-always-working-like-it-should/20997828#20997828 –

Respuesta

1

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

En cualquier caso ver si esto ayuda: smoothScrollToPosition after notifyDataSetChanged not working in android

+0

sí ... Cometí un error aquí en el foro, es, por supuesto, listview.smoothScrollToPosition (pos) y listview.setSelection (pos). y notifyDataSetChanged se llama automáticamente al llamar a arrayadapter.add() .., de lo contrario, setSelection no funcionaría – user1515520

+1

es simplemente extraño que setSelection (pos) funcione perfectamente, pero smoothScrollToPosition (pos) no funciona, ¿verdad? – user1515520

5

método setSelection() que debe utilizar.

+2

No es necesariamente lo mismo, es posible que no desee que se seleccione el elemento, o simplemente puede estar buscando el efecto suave – mdelolmo

+0

Realmente me ayudó, en lugar de pasar nada, todavía se desplaza hasta el final de la lista. – Slickelito

+1

'setSelection' de hecho funciona donde' smoothScrollToPosition' no funciona, pero sería útil si nos puede indicar por qué es así. –

51

Probablemente desee decirle al ListView que publique el desplazamiento cuando el hilo 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 usted debe hacer algo como:

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

+1 para la idea de 'publicar'. Sin embargo, me encontré con casos donde 'smoothScrollToPosition' todavía no funciona, dejando un pequeño espacio de desplazamiento entre la parte superior del widget y el elemento en la posición para desplazarse. En estos casos, 'setSelection' (combinado con' post' por supuesto) funciona sin problemas. –

+0

Sí, yo también. ListViews son mucho menos que UITableView y tal. Es triste, porque las listas son un concepto central en los dispositivos móviles donde el tamaño de la pantalla se ve comprometido, por lo que tenemos que desplazar cosas. En cualquier caso, para que lo sepas, el desplazamiento funciona, solo tienes que entender las reglas, el diseño debe haber sido establecido, debes hacerlo en el hilo de la interfaz de usuario, debes publicarlo para que la lista pueda poner en cola la operación, etc. Debe haber mucha magia para que ocurra el pergamino. Estoy seguro de que @RomanianGuy puede arrojar más luz sobre esto. Sin embargo, la implementación de iSO funciona sin problemas en su mayor parte. –

+5

El nombre del tipo es @RomainGuy BTW. –

11

(Copiado de mi respuesta: smoothScrollToPositionFromTop() is not always working like it should)

Esto es un error conocido. Verhttps://code.google.com/p/android/issues/detail?id=36062

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

Primera llamada smothScrollToPositionFromTop(position) y luego, cuando el desplazamiento ha terminado, llamar 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.

he implementado esta solución dentro de los 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; 
    } 
} 
+0

Esta es la respuesta correcta, ¡gracias! – FireZenk

2

El método de selección de conjunto mencionado por funciona Lars, pero la animación era demasiado nerviosa para nuestros propósitos mientras se salta 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.

1
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); 
Cuestiones relacionadas