Behalten Sie die Bildlaufposition beim Hinzufügen zu ListView mit umgekehrtem Endlos-Bildlauf bei

StackOverflow https://stackoverflow.com//questions/22051556

Frage

Ich erstelle eine Chat-ähnliche Android-Anwendung, ähnlich wie Hangouts.Zu diesem Zweck verwende ich eine vertikale ListView mit stackFromBottom=true Und transcriptMode="normal".

Die Liste ist von älteren Nachrichten (oben) zu jüngeren Nachrichten (unten) sortiert.Im Normalzustand wird die ListView nach unten gescrollt und zeigt die jüngste Nachricht an.

Die ListView verwendet einen umgekehrten Endlos-Scroll-Adapter, um weitere (ältere) Nachrichten zu laden, sobald der Benutzer an den Anfang der Liste scrollt.Sobald ältere Nachrichten geladen sind, werden sie oben in der Liste hinzugefügt.

Das gewünschte Verhalten besteht darin, dass ListView seine Bildlaufposition bis zum Ende der Liste beibehält, wenn ältere Nachrichten oben hinzugefügt werden.Das heißt, wenn ältere Nachrichten oben hinzugefügt werden, sollte die Scroll-Ansicht dieselben Nachrichten anzeigen, die vor dem Hinzufügen der älteren Nachrichten angezeigt wurden.

Leider funktioniert das nicht.Anstatt die Bildlaufposition nach unten beizubehalten, Die ListView behält die Bildlaufposition zum Anfang der Liste bei.Das heißt, nachdem ältere Nachrichten zur Liste hinzugefügt wurden, zeigt die Liste die obersten (d. h. ältesten) Nachrichten an.

Gibt es eine einfache Möglichkeit, ListView anzuweisen, seine Bildlaufposition nach unten statt nach oben beizubehalten, wenn neue Elemente oben hinzugefügt werden?

Aktualisieren

Zu Demonstrationszwecken habe ich den Anwendungsfall und den Code so weit wie möglich minimiert.Das folgende Beispiel erstellt eine einfache String-Array-Liste.Wenn Sie auf ein Element klicken, wird oben in der Liste ein weiteres Element hinzugefügt.Wenn Sie lange auf ein Element klicken, wird am Ende der Liste ein weiteres Element hinzugefügt.

Beim Hinzufügen von Elementen am Ende der Liste (langes Klicken) funktioniert alles einwandfrei.Beim Hinzufügen von Elementen oben in der Liste (einfacher Klick) gibt es drei Fälle:

  • Wenn die Liste nach unten gescrollt wurde, funktioniert alles einwandfrei.Nachdem Sie das Element oben hinzugefügt haben, wird die Liste weiterhin nach unten gescrollt.
  • Wenn die Liste nicht nach unten (oder nach oben) gescrollt wird, behält die Liste ihre Scroll-y-Position (von oben) bei.Dadurch scheint die Liste um ein Element nach oben zu „springen“.Ich möchte, dass die Liste in diesem Fall nicht „nach oben springt“, d. h. ich möchte, dass sie ihre Scroll-Position von unten beibehält.
  • Wird die Liste nach oben gescrollt, dann passiert das Gleiche wie im Fall 2.Das bevorzugte Verhalten ist das gleiche wie in Fall 2.

(Die letzten beiden Fälle sind tatsächlich die gleichen.Ich habe sie getrennt, weil das Problem im Fall 2 besser dargestellt werden kann.)

Code

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;
      }
    });
  }
}
War es hilfreich?

Lösung

Ich habe das herausgefunden.Überall dort, wo Sie neue Daten erhalten, rufe ich Folgendes auf, bevor ich Daten im Adapter ändere:

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

Dann rufe ich an:

adapter.setData(data);

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

Andere Tipps

Holen Sie sich zuerst die firstVisiblePosition (oder die letzte, seit sie auf dem Kopf steht).Sie müssen versuchen, es selbst zu überprüfen) und dann den Anfang der Ansicht abrufen, die der Liste hinzugefügt wird, und dann mit der Methode setSe;ectionFromTop() zum gewünschten Ort scrollen.

Code:

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

Quelle.

Bearbeiten, um zusätzliche Informationen zu erhalten:

Ich glaube, ich habe Ihr Problem gefunden.Ich habe Ihre beschriebenen Anwendungsfälle repliziert, indem ich eine eigenständige Liste als einzige Ansicht in XML verwendet habe:

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

Ich habe das Problem behoben, Ihren gewünschten Anwendungsfällen zu folgen, indem ich das Layout in einem übergeordneten Layout verschachtelt habe:

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

Nachdem Sie den Datensatz in Ihren Adapter eingelegt haben, können Sie ihn verwenden

   yourListView.setSelection(yourAdapter.getCount() - 1);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top