414 Stimmen

Beibehalten/Speichern/Wiederherstellen der Bildlaufposition bei der Rückkehr zu einer ListView

Ich habe eine lange ListView dass der Benutzer einen Bildlauf durchführen kann, bevor er zum vorherigen Bildschirm zurückkehrt. Wenn der Benutzer diese Seite öffnet ListView Ich möchte, dass die Liste wieder an die gleiche Stelle wie zuvor gescrollt wird. Irgendwelche Ideen, wie man das erreichen kann?

1voto

Andrew Sneck Punkte 526

DIE BESTE LÖSUNG IST:

// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());

// ...

// restore index and position
mList.post(new Runnable() {
    @Override
    public void run() {
      mList.setSelectionFromTop(index, top);
   }
});

SIE MÜSSEN IN DER POST UND IM THREAD ANRUFEN!

1voto

Michael Peterson Punkte 9656

Sie können den Bildlaufstatus nach einem Neuladen beibehalten, wenn Sie den Status vor dem Neuladen speichern und ihn danach wiederherstellen. In meinem Fall habe ich eine asynchrone Netzwerkanfrage gestellt und die Liste in einem Callback nach Abschluss der Anfrage neu geladen. Hier stelle ich den Zustand wieder her. Codebeispiel ist Kotlin.

val state = myList.layoutManager.onSaveInstanceState()

getNewThings() { newThings: List<Thing> ->

    myList.adapter.things = newThings
    myList.layoutManager.onRestoreInstanceState(state)
}

0voto

befstrat Punkte 439

Zur Verdeutlichung der hervorragenden Antwort von Ryan Newsom und sie für Fragmente und für den üblichen Fall anzupassen, dass wir von einem "Master"-ListView-Fragment zu einem "Details"-Fragment und dann zurück zum "Master" navigieren wollen

    private View root;
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
           if(root == null){
             root = inflater.inflate(R.layout.myfragmentid,container,false);
             InitializeView(); 
           } 
           return root; 
        }

    public void InitializeView()
    {
        ListView listView = (ListView)root.findViewById(R.id.listviewid);
        BaseAdapter adapter = CreateAdapter();//Create your adapter here
        listView.setAdpater(adapter);
        //other initialization code
    }

Die "Magie" besteht darin, dass die Ansicht nicht neu erstellt wird, wenn wir vom Detailfragment zum ListView-Fragment zurücknavigieren, wir setzen den Adapter des ListViews nicht, also bleibt alles so, wie wir es verlassen haben!

0voto

John T Punkte 619

Ich benutze FirebaseListAdapter und konnte keine der Lösungen zum Laufen bringen. Am Ende habe ich dies getan. Ich vermute, es gibt elegantere Wege, aber dies ist eine vollständige und funktionierende Lösung.

Vor onCreate:

private int reset;
private int top;
private int index;

Innerhalb des FirebaseListAdapters:

@Override
public void onDataChanged() {
     super.onDataChanged();

     // Only do this on first change, when starting
     // activity or coming back to it.
     if(reset == 0) {
          mListView.setSelectionFromTop(index, top);
          reset++;
     }

 }

onStart:

@Override
protected void onStart() {
    super.onStart();
    if(adapter != null) {
        adapter.startListening();
        index = 0;
        top = 0;
        // Get position from SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        top = sharedPref.getInt("TOP_POSITION", 0);
        index = sharedPref.getInt("INDEX_POSITION", 0);
        // Set reset to 0 to allow change to last position
        reset = 0;
    }
}

onStop:

@Override
protected void onStop() {
    super.onStop();
    if(adapter != null) {
        adapter.stopListening();
        // Set position
        index = mListView.getFirstVisiblePosition();
        View v = mListView.getChildAt(0);
        top = (v == null) ? 0 : (v.getTop() - mListView.getPaddingTop());
        // Save position to SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.edit().putInt("TOP_POSITION" + "", top).apply();
        sharedPref.edit().putInt("INDEX_POSITION" + "", index).apply();
    }
}

Da ich dies auch für die folgenden Fälle lösen musste FirebaseRecyclerAdapter Auch dafür poste ich hier die Lösung:

Vor onCreate:

private int reset;
private int top;
private int index;

Innerhalb des FirebaseRecyclerAdapters:

@Override
public void onDataChanged() {
    // Only do this on first change, when starting
    // activity or coming back to it.
    if(reset == 0) {
        linearLayoutManager.scrollToPositionWithOffset(index, top);
        reset++;
    }
}

onStart:

@Override
protected void onStart() {
    super.onStart();
    if(adapter != null) {
        adapter.startListening();
        index = 0;
        top = 0;
        // Get position from SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        top = sharedPref.getInt("TOP_POSITION", 0);
        index = sharedPref.getInt("INDEX_POSITION", 0);
        // Set reset to 0 to allow change to last position
        reset = 0;
    }
}

onStop:

@Override
protected void onStop() {
    super.onStop();
    if(adapter != null) {
        adapter.stopListening();
        // Set position
        index = linearLayoutManager.findFirstVisibleItemPosition();
        View v = linearLayoutManager.getChildAt(0);
        top = (v == null) ? 0 : (v.getTop() - linearLayoutManager.getPaddingTop());
        // Save position to SharedPrefs
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.edit().putInt("TOP_POSITION" + "", top).apply();
        sharedPref.edit().putInt("INDEX_POSITION" + "", index).apply();
    }
}

0voto

Rohit Lalwani Punkte 388

Verwenden Sie den unten stehenden Code:

int index,top;

@Override
protected void onPause() {
    super.onPause();
    index = mList.getFirstVisiblePosition();

    View v = challengeList.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
}

und jedes Mal, wenn Sie Ihre Daten aktualisieren, verwenden Sie den folgenden Code:

adapter.notifyDataSetChanged();
mList.setSelectionFromTop(index, top);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X