android - que - Actualizar datos en RecyclerView y mantener su posición de desplazamiento
oncreateviewholder que es (13)
Eso me funciona en Kotlin.
- Cree el adaptador y entregue sus datos en el constructor
class LEDRecyclerAdapter (var currentPole: Pole): RecyclerView.Adapter<RecyclerView.ViewHolder>() { ... }
- cambie esta propiedad y llame a notifyDataSetChanged ()
adapter.currentPole = pole
adapter.notifyDataSetChanged()
El desplazamiento del desplazamiento no cambia.
¿Cómo se actualizan los datos que se muestran en
RecyclerView
(llamando a
notifyDataSetChanged
en su adaptador) y se asegura de que la posición de desplazamiento se restablezca exactamente donde estaba?
En el caso de un buen ''
ListView
'', todo lo que se necesita es recuperar
getChildAt(0)
, verificar su
getTop()
y llamar a
setSelectionFromTop
con los mismos datos exactos después.
No parece ser posible en el caso de
RecyclerView
.
Supongo que se supone que debo usar su
LayoutManager
que de hecho proporciona
scrollToPositionWithOffset(int position, int offset)
, pero ¿cuál es la forma correcta de recuperar la posición y el offset?
layoutManager.findFirstVisibleItemPosition()
y
layoutManager.getChildAt(0).getTop()
?
¿O hay una forma más elegante de hacer el trabajo?
La respuesta superior de @DawnYu funciona, pero la vista del reciclador primero se desplazará hacia la parte superior, luego volverá a la posición de desplazamiento deseada causando una reacción de "parpadeo" que no es agradable.
Para actualizar el recyclerView, especialmente después de venir de otra actividad, sin parpadear y mantener la posición de desplazamiento, debe hacer lo siguiente.
- Asegúrese de actualizar su vista de reciclador utilizando DiffUtil. Lea más sobre eso aquí: https://www.journaldev.com/20873/android-recyclerview-diffutil
- Al reanudar su actividad, o en el momento en que desea actualizar su actividad, cargue los datos en su vista de reciclador. Usando diffUtil, solo las actualizaciones se realizarán en la vista del reciclador mientras se mantiene en su posición.
Espero que esto ayude.
Mantenga la posición de desplazamiento usando la respuesta @DawnYu para envolver
notifyDataSetChanged()
esta manera:
val recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState()
adapter.notifyDataSetChanged()
recyclerView.layoutManager?.onRestoreInstanceState(recyclerViewState)
No he usado Recyclerview pero lo hice en ListView. Código de muestra en Recyclerview:
setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
rowPos = mLayoutManager.findFirstVisibleItemPosition();
Es el oyente cuando el usuario se desplaza. La sobrecarga de rendimiento no es significativa. Y la primera posición visible es precisa de esta manera.
Quizás esto es demasiado simple, pero hago esto simplemente llamando
recreate();
Mi posición de vista de reciclador se guarda.
Sí, puede resolver este problema haciendo el constructor del adaptador solo una vez, estoy explicando la parte de codificación aquí:
if (appointmentListAdapter == null) {
appointmentListAdapter = new AppointmentListAdapter(AppointmentsActivity.this);
appointmentListAdapter.addAppointmentListData(appointmentList);
appointmentListAdapter.setOnStatusChangeListener(onStatusChangeListener);
appointmentRecyclerView.setAdapter(appointmentListAdapter);
} else {
appointmentListAdapter.addAppointmentListData(appointmentList);
appointmentListAdapter.notifyDataSetChanged();
}
Ahora puede ver que he comprobado que el adaptador es nulo o no y solo se inicializa cuando es nulo.
Si el adaptador no es nulo, estoy seguro de que he inicializado mi adaptador al menos una vez.
Así que solo agregaré la lista al adaptador y llamaré a notifydatasetchanged.
RecyclerView siempre mantiene la última posición desplazada, por lo tanto, no tiene que almacenar la última posición, solo llame a notifydatasetchanged, la vista del reciclador siempre actualiza los datos sin ir al principio.
Gracias feliz codificación
Si tiene uno o más EditTexts dentro de los elementos de una vista de reciclaje, desactive el enfoque automático de estos, colocando esta configuración en la vista principal de la vista de reciclaje:
android:focusable="true"
android:focusableInTouchMode="true"
Tuve este problema cuando comencé otra actividad iniciada desde un elemento de la vista del reciclador, cuando regresé y configuré una actualización de un campo en un elemento con notifyItemChanged (posición) el desplazamiento de los movimientos de RV, y mi conclusión fue que, el enfoque automático de EditText Artículos, el código anterior resolvió mi problema.
mejor.
Simplemente regrese si la antigua Posición y posición es la misma;
private int oldPosition = -1;
public void notifyItemSetChanged(int position, boolean hasDownloaded) {
if (oldPosition == position) {
return;
}
oldPosition = position;
RLog.d(TAG, " notifyItemSetChanged :: " + position);
DBMessageModel m = mMessages.get(position);
m.setVideoHasDownloaded(hasDownloaded);
notifyItemChanged(position, m);
}
Tengo un problema bastante similar Y se me ocurrió la siguiente solución.
El uso de
notifyDataSetChanged
es una mala idea.
Debería ser más específico, entonces
RecyclerView
guardará el estado de desplazamiento para usted.
Por ejemplo, si solo necesita actualizar, o en otras palabras, desea volver a modificar cada vista, simplemente haga esto:
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
Tuve este problema con una lista de elementos que cada uno tenía un tiempo en minutos hasta que se ''vencían'' y debían actualizarse. Actualizaría los datos y luego, llamar
orderAdapter.notifyDataSetChanged();
y se desplazaría a la cima cada vez. Reemplacé eso con
for(int i = 0; i < orderArrayList.size(); i++){
orderAdapter.notifyItemChanged(i);
}
Y estuvo bien. Ninguno de los otros métodos en este hilo funcionó para mí. Sin embargo, al usar este método, hizo que cada elemento individual parpadeara cuando se actualizó, por lo que también tuve que poner esto en onCreateView del fragmento principal
RecyclerView.ItemAnimator animator = orderRecycler.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
}
Yo uso este. ^ _ ^
// Save state
private Parcelable recyclerViewState;
recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();
// Restore state
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
Es más simple, ¡espero que te ayude!
EDITAR: Para restaurar exactamente la misma posición aparente , como en, para que se vea exactamente como se veía, necesitamos hacer algo un poco diferente (vea a continuación cómo restaurar el valor exacto de desplazamiento):
Guarde la posición y desplace de esta manera:
LinearLayoutManager manager = (LinearLayoutManager) mRecycler.getLayoutManager();
int firstItem = manager.findFirstVisibleItemPosition();
View firstItemView = manager.findViewByPosition(firstItem);
float topOffset = firstItemView.getTop();
outState.putInt(ARGS_SCROLL_POS, firstItem);
outState.putFloat(ARGS_SCROLL_OFFSET, topOffset);
Y luego restaure el pergamino así:
LinearLayoutManager manager = (LinearLayoutManager) mRecycler.getLayoutManager();
manager.scrollToPositionWithOffset(mStatePos, (int) mStateOffset);
Esto restaura la lista a su posición aparente exacta. Aparentemente porque se verá igual para el usuario, pero no tendrá el mismo valor de desplazamiento (debido a las posibles diferencias en las dimensiones del diseño horizontal / vertical).
Tenga en cuenta que esto solo funciona con LinearLayoutManager.
--- A continuación, cómo restaurar el desplazamiento exacto, lo que probablemente hará que la lista se vea diferente ---
-
Aplique un OnScrollListener así:
private int mScrollY; private RecyclerView.OnScrollListener mTotalScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); mScrollY += dy; } };
Esto almacenará la posición exacta de desplazamiento en todo momento en mScrollY.
-
Almacene esta variable en su paquete y restaure la restauración de estado en una variable diferente , la llamaremos mStateScrollY.
-
Después de la restauración del estado y después de que su RecyclerView haya restablecido todos sus datos, restablezca el desplazamiento con esto:
mRecyclerView.scrollBy(0, mStateScrollY);
Eso es.
Tenga cuidado, ya que restaura el desplazamiento a una variable diferente, esto es importante, porque se llamará a OnScrollListener con .scrollBy () y, posteriormente, establecerá mScrollY en el valor almacenado en mStateScrollY. Si no lo hace, mScrollY tendrá el doble del valor de desplazamiento (porque OnScrollListener funciona con deltas, no con desplazamientos absolutos).
El ahorro de estado en actividades se puede lograr así:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(ARGS_SCROLL_Y, mScrollY);
}
Y para restaurar, llame a esto en su onCreate ():
if(savedState != null){
mStateScrollY = savedState.getInt(ARGS_SCROLL_Y, 0);
}
El ahorro de estado en fragmentos funciona de manera similar, pero el ahorro de estado real necesita un poco de trabajo extra, pero hay muchos artículos que se ocupan de eso, por lo que no debería tener problemas para descubrir cómo, los principios de guardar el desplazamiento. y restaurarlo sigue siendo el mismo.
mMessageAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
mLayoutManager.smoothScrollToPosition(mMessageRecycler, null, mMessageAdapter.getItemCount());
}
});
La solución aquí es seguir desplazándose por la vista del reciclador cuando llega un nuevo mensaje.
El método onChanged () detecta la acción realizada en la vista de reciclaje.