programacion - listview dinamico android studio
Mantenga la posiciĆ³n de desplazamiento cuando agregue a ListView con desplazamiento inverso sin fin (4)
Estoy creando una aplicación de Android similar a un chat, similar a Hangouts. Para este propósito estoy usando un ListView vertical con stackFromBottom=true
y transcriptMode="normal"
.
La lista está ordenada desde mensajes más antiguos (arriba) a mensajes más jóvenes (abajo). En estado normal, el ListView se desplaza hacia la parte inferior, mostrando el mensaje más joven.
El ListView utiliza un adaptador de desplazamiento sin fin inverso para cargar más mensajes (más antiguos) una vez que el usuario se desplaza a la parte superior de la lista. Una vez que se cargan los mensajes más antiguos, se agregan a la parte superior de la lista.
El comportamiento deseado es que el ListView mantiene su posición de desplazamiento al final de la lista, cuando los mensajes más antiguos se agregan a la parte superior de la lista. Es decir, cuando los mensajes más antiguos se agregan a la parte superior, la vista de desplazamiento debe mostrar los mismos mensajes que se mostraron antes de agregar los mensajes más antiguos.
Por desgracia, esto no funciona. En lugar de mantener la posición de desplazamiento hacia abajo, ListView mantiene la posición de desplazamiento hacia la parte superior de la lista . Es decir, después de agregar mensajes antiguos a la lista, la lista muestra los mensajes más importantes (es decir, los más antiguos).
¿Hay una manera fácil de decirle a ListView que mantenga su posición de desplazamiento hacia abajo, en lugar de la parte superior, al agregar nuevos elementos a la parte superior?
Actualizar
Para fines de demostración, he minimizado el caso de uso y el código tanto como sea posible. El siguiente ejemplo crea una lista de matriz de cadena simple. Al hacer clic en un elemento, se agregará otro elemento en la parte superior de la lista. Al hacer clic en un elemento durante más tiempo, se agregará otro elemento al final de la lista.
Todo funciona bien al agregar elementos al final de la lista (clic largo). Al agregar elementos en la parte superior de la lista (clic simple), hay 3 casos:
- Si la lista se desplazó a la parte inferior, entonces todo funciona bien. Después de agregar el elemento a la parte superior, la lista aún se desplaza a la parte inferior.
- Si la lista no se desplaza hacia abajo (ni hacia arriba), la lista mantendrá su posición de desplazamiento-y (desde arriba). Esto hace que la lista parezca "saltar" un elemento hacia arriba. Me gustaría que la lista no "saltara" en este caso, es decir, me gustaría que mantuviera su posición de desplazamiento-y desde la parte inferior.
- Si la lista se desplaza hacia la parte superior, entonces sucede lo mismo que en el caso 2. El comportamiento preferido es el mismo que el caso 2.
(De hecho, los 2 últimos casos son los mismos. Los separé porque el problema se puede demostrar mejor en el caso 2.)
Código
public class MyListActivity extends Activity {
int topIndex = 1;
int bottomIndex = 20;
protected final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_list_activity);
final ListView list = (ListView) findViewById(R.id.list);
list.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
list.setStackFromBottom(true);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1);
for (int i = topIndex; i <= bottomIndex; i++) {
adapter.add(Integer.toString(i));
}
list.setAdapter(adapter);
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
adapter.insert(Integer.toString(--topIndex), 0);
}
});
list.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
adapter.add(Integer.toString(++bottomIndex));
return true;
}
});
}
}
Después de insertar el registro en su adaptador, puede intentar usar
yourListView.setSelection(yourAdapter.getCount() - 1);
Editar para tener en cuenta la información adicional:
Creo que he encontrado tu problema. Repliqué sus casos de uso descritos utilizando una lista independiente como la única vista en XML:
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
Solucioné el problema para seguir los casos de uso deseados al anidar el diseño en un diseño principal:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>
</FrameLayout>
He resuelto esto Donde sea que esté obteniendo datos nuevos, llamo a lo siguiente antes de cambiar los datos en el adaptador:
int firstVisibleItem = list.getFirstVisiblePosition();
int oldCount = adapter.getCount();
View view = list.getChildAt(0);
int pos = (view == null ? 0 : view.getBottom());
Entonces llamo:
adapter.setData(data);
list.setSelectionFromTop(firstVisibleItem + adapter.getCount() - oldCount + 1, pos);
Primero obtenga la primera posición visible (o la última desde su posición invertida. Debo intentarlo y verificarlo usted mismo) y luego obtener la parte superior de la vista que se agrega a la lista y luego usando el método setSe; ectionFromTop (), puede desplazarse a la ubicación deseada.
Código:
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0); //or upside down (list.size - 1)
int top = (v == null) ? 0 : v.getTop(); //returns the top of the view its Y co-ordinates. [Doc][1]
mList.setSelectionFromTop(index, top);