Ci scusiamo per il mio scarso inglese.Come salvare e ripristinare la posizione esatta di scorrimento di RecyclerView?
Voglio la posizione esatta. E dopo l'attività /frammento è stato distrutto (non importa distruggo o il sistema distrugge), ho riaprire l'attività/frammento, il RecyclerView
può anche come lo stesso posizione come è stato distrutto.
Lo "lo stesso" non significa "posizione articolo", perché forse l'elemento viene visualizzato solo parzialmente l'ultima volta.
Voglio ripristinare la stessa identica posizione.
Ho provato alcuni modi sotto, ma nessuno è perfetto.
Qualcuno può aiutare?
1. Primo passo.
Io uso onScrolled
per calcolare la posizione esatta di scorrimento, quando lo scorrimento si ferma, salvare la posizione. Quando lo spinner modifica il set di dati o frammento onCreat, ripristina la posizione del set di dati scelto. Alcuni set di dati possono avere molte molte righe.
Può salvare e ripristinare dopo che l'app è stata distrutta, ma forse ci sono troppi calcoli?
causerà
Skipped 60 frames! The application may be doing too much work on its main thread. attempt to finish an input event but the input event receiver has already been disposed. android total arena pages for jit.
E se scrollY
è enorme, come 111111
, quando è aperto il frammento, il RecyclerView in primo luogo mostrare la lista inizia dalla prima voce, e con un certo ritardo, scorre alla posizione scrollY
.
Come fare senza indugio?
recyclerView.addOnScrollListener(new OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, final int dy) {
super.onScrolled(recyclerView, dx, dy);
handler.post(new Runnable() {
@Override
public void run() {
if (isTableSwitched) {
scrollY = 0;
isTableSwitched = false;
}
scrollY = scrollY + dy;
Log.i("dy——scrollY——table", String.valueOf(dy) + "——" + String.valueOf(scrollY) + tableName);
}
});
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
saveRecyclerPosition(tableName, scrollY);
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
break;
case RecyclerView.SCROLL_STATE_SETTLING:
break;
}
}
});
public void saveRecyclerPosition(String tableName, int y) {
prefEditorSettings.putInt(KEY_SCROLL_Y + tableName, y);
prefEditorSettings.commit();
}
public void restoreRecyclerViewState(final String tableName) {
handler.post(new Runnable() {
@Override
public void run() {
recyclerView.scrollBy(0, prefSettings.getInt(KEY_SCROLL_Y + tableName, 0));
}
});
}
//use Spinner to choose dataset
spnWordbook.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
isTableSwitched = true;
tableName= parent.getItemAtPosition(position).toString();
prefEditorSettings.putString(KEY_SPINNER_SELECTED_TABLENAME, tableName);
prefEditorSettings.commit();
wordsList = WordsManager.getWordsList(tableName);
wordCardAdapter.updateList(wordsList);
restoreRecyclerViewState(tableName);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
2.Seconda modo.
Questo funziona perfettamente, ma può funzionare solo nel ciclo di vita del frammento.
Provo a utilizzare ObjectOutputStream
e ObjectInputStream
per salvare e ripristinare il HashMap
, ma non funziona.
Come salvarlo in memoria?
private HashMap <String, Parcelable> hmRecyclerViewState = new HashMap<String, Parcelable>();
public void saveRecyclerPosition(String tableName) {
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();
hmRecyclerViewState.put(tableName, recyclerViewState);
}
public void restoreRecyclerViewState(final String tableName) {
if (hmRecyclerViewState.get(tableName) != null) {
recyclerViewState = hmRecyclerViewState.get(tableName);
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
recyclerViewState = null;
}
3.Terza modo.
I cambiare il secondo modo, utilizzare Bundle
anziché HashMap
, ma ha la stessa domanda, non funziona quando fuori del ciclo di vita frammento.
Io uso manually serialize/deserialize android bundle per salvare bundle
nella memoria, ma quando lo ripristino, non ottiene lo bundle
valido.
========================================= ========================= La soluzione
Grazie a tutti!
Infine ho risolvere questo problema, è possibile vederlo in my code, basta vedere questi 2 metodi: saveRecyclerViewPosition e restoreWordRecyclerViewPosition.
probabilmente ottieni solo il primo ID elemento visualizzato e il relativo offset dal layoutmanager, quindi puoi passare alla posizione su come ricreare e regolare lo scorrimento per l'offset. questo probabilmente funzionerà anche se il set di dati è cambiato nel frattempo. –
@ bleeding182 grazie. Anch'io ho pensato in questo modo, ma non so come ottenere l'offset di un articolo? ogni elemento ha un'altezza diversa – DawnYu
è possibile ottenere la vista dal layoutmanager, quindi leggere getTop() o getDecoratedTop(), la differenza tra quello e il recyclerview.top sarà l'offset;) E anche se non si ottiene l'offset giusto, sarai almeno nella giusta posizione senza saltare i fotogrammi –