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?
Antworten
Zu viele Anzeigen?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!
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)
}
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!
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();
}
}
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);