Domanda

Sto costruendo un'applicazione Android come chat, simile agli hangouts. A tale scopo sto usando una valida di lista verticale con stackFromBottom=true e transcriptMode="normal".

L'elenco è ordinato da messaggi precedenti (in alto) ai messaggi più giovani (in basso). Nello stato normale, il ListView è scorretto verso il basso, mostrando il messaggio più giovane.

ListView utilizza un adattatore a scorrimento a rovescio inverso per caricare i messaggi più anziani) una volta che l'utente scorre verso la parte superiore dell'elenco. Una volta caricati i messaggi più vecchi, vengono aggiunti alla parte superiore dell'elenco.

Il comportamento desiderato è che la ListView mantiene la sua posizione di scorrimento nella parte inferiore dell'elenco, quando i messaggi più vecchi vengono aggiunti alla parte superiore. Cioè, quando i messaggi più vecchi vengono aggiunti all'inizio, la vista di scorrimento dovrebbe mostrare gli stessi messaggi visualizzati prima di aggiungere i messaggi più vecchi.

Sfortunatamente, questo non funziona. Invece di mantenere la posizione di scorrimento verso il basso, La ListView mantiene la posizione di scorrimento nella parte superiore dell'elenco . Cioè, dopo aver aggiunto messaggi precedenti all'elenco, l'elenco mostra i messaggi principali (I.e più antichi).

Esiste un modo semplice per indicare alla ListView per mantenere la sua posizione di scorrimento verso il basso, invece della parte superiore, quando si aggiungono nuovi elementi alla parte superiore?

Aggiornamento

Ai fini della dimostrazione, ho minimizzato il caso dell'uso e il codice il più possibile. L'esempio seguente crea una semplice lista di array di stringa. Facendo clic su un oggetto aggiungerà un altro elemento nella parte superiore dell'elenco. Facendo appieno a lungo clic su un oggetto aggiungerà un altro elemento nella parte inferiore dell'elenco.

Tutto funziona correttamente quando si aggiungono elementi nella parte inferiore dell'elenco (clic con mandato a lungo). Quando si aggiungono elementi nella parte superiore dell'elenco (semplice clic), quindi ci sono 3 casi:

    .
  • Se l'elenco è stato scrollato fino in fondo, tutto funziona bene. Dopo aver aggiunto l'elemento all'inizio, l'elenco è ancora scorretto verso il basso.
  • Se l'elenco non è scrollato in basso (né in alto), l'elenco manterrà la sua posizione di scorrimento-y (dall'alto in alto). Questo rende la lista per "saltare" un elemento in alto. Vorrei che la lista non "salti" in questo caso, cioè mi piacerebbe mantenere la sua posizione di scorrimento dal basso.
  • Se l'elenco viene sfilato verso l'alto, allora lo stesso accade come nel caso 2. Il comportamento preferito è lo stesso come caso 2.

(gli ultimi 2 casi sono in realtà lo stesso. Li ho separati perché il problema può essere meglio dimostrato nella causa 2.)

Codice

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

È stato utile?

Soluzione

L'ho capito.Ovunque sia che tu stia ottenendo nuovi dati, chiamare quanto segue prima di modificare i dati nell'adattatore:

int firstVisibleItem = list.getFirstVisiblePosition();
int oldCount = adapter.getCount();
View view = list.getChildAt(0);
int pos = (view == null ? 0 :  view.getBottom());
.

Allora chiamo:

adapter.setData(data);

list.setSelectionFromTop(firstVisibleItem + adapter.getCount() - oldCount + 1, pos);
.

Altri suggerimenti

Prima ottenere la prima stesposizione (o l'ultima da quando è sottosopra. Hai dovuto provare a controllarlo da solo) e quindi ottenere la parte superiore della vista che viene aggiunta all'elenco e quindi utilizzare il metodo SETSE; ECLYFROMOP (),È possibile scorrere fino alla posizione desiderata.

Codice:

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

origine.

Modifica per account per ulteriori informazioni:

Penso di aver trovato il tuo problema.Ho replicato i casi di utilizzo descritti utilizzando un elenco standalone come solo vista in XML:

<ListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</ListView>
.

Ho riparato il problema per seguire i tuoi casi di utilizzo desiderati annidando il layout in un layout genitore:

<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>
.

Dopo aver inserito il record nel tuo adattatore puoi provare a utilizzare

   yourListView.setSelection(yourAdapter.getCount() - 1);
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top