java - ¿Cómo desplazarse hasta la parte inferior de un RecyclerView? scrollToPosition no funciona
recyclerview auto scroll (17)
Agregue este código después de enviar el mensaje y antes de recibir el mensaje del servidor
recyclerView.scrollToPosition(mChatList.size() - 1);
Me gustaría desplazarme al final de la lista RecyclerView después de cargar la actividad.
GENERIC_MESSAGE_LIST = (ArrayList) intent.getExtras().getParcelableArrayList(ConversationsAdapter.EXTRA_MESSAGE);
conversationView = (RecyclerView) findViewById(R.id.list_messages);
conversationView.setHasFixedSize(true);
conversationViewLayoutManager = new LinearLayoutManager(this);
conversationView.setLayoutManager(conversationViewLayoutManager);
conversationViewAdapter = new ConversationAdapter(GENERIC_MESSAGE_LIST, this);
conversationView.setAdapter(conversationViewAdapter);
conversationView.scrollTo(...)
arroja una excepción sobre no ser compatible con RecyclerView, y la
conversationView.scrollToPosition(...)
no parece hacer nada.
Después del bloque de código anterior, agregué
conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size() + 1)
que no funciona
Hay 30 elementos en
GENERIC_MESSAGE_LIST
.
Cuando llama a
setAdapter
, eso no establece y coloca inmediatamente los elementos en la pantalla (que requiere una sola pasada de diseño), por lo tanto, su llamada
scrollToPosition()
no tiene elementos reales a los que desplazarse cuando la llama.
En su lugar, debe registrar un
ViewTreeObserver.OnGlobalLayoutListener
(a través de
addOnGlobalLayoutListner()
desde un
ViewTreeObserver
creado por
conversationView.getViewTreeObserver()
) que retrasa su
scrollToPosition()
hasta después del primer pase de diseño:
conversationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
conversationView.scrollToPosition(GENERIC_MESSAGE_LIST.size();
// Unregister the listener to only call scrollToPosition once
conversationView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// Use vto.removeOnGlobalLayoutListener(this) on API16+ devices as
// removeGlobalOnLayoutListener is deprecated.
// They do the same thing, just a rename so your choice.
}
});
Desplácese por primera vez cuando ingrese en la vista del reciclador por primera vez, luego use linearLayoutManager.scrollToPositionWithOffset (messageHashMap.size () - 1, ponga menos para desplazarse hacia abajo para desplazarse hacia arriba, poner en valor positivo);
si la vista es muy grande en altura, entonces la posición de desplazamiento se usa un desplazamiento particular para la parte superior de la vista, entonces usa
int globalXScroldl = chatMessageBinding.rvChat.computeVerticalScrollOffset (); chatMessageBinding.rvChat.smoothScrollBy (0, Math.abs (OverallXScroldl));
En Kotlin:
recyclerView.viewTreeObserver.addOnGlobalLayoutListener { scrollToEnd() }
private fun scrollToEnd() =
(adapter.itemCount - 1).takeIf { it > 0 }?.let(recyclerView::smoothScrollToPosition)
En mi caso, donde las vistas no tienen la misma altura, llamar a scrollToPosition en el LayoutManager funcionó para desplazarse realmente hacia la parte inferior y ver completamente el último elemento:
recycler.getLayoutManager().scrollToPosition(adapter.getItemCount() - 1);
Estaba mirando esta publicación para encontrar la respuesta, pero ... Creo que todos en esta publicación se enfrentaban al mismo escenario que yo:
scrollToPosition()
fue completamente ignorado, por una razón evidente.
¿Qué estaba usando?
recyclerView.scrollToPosition(items.size());
... ¿qué funcionó ?
recyclerView.scrollToPosition(items.size() - 1);
Esto funciona perfectamente bien para mí:
AdapterChart adapterChart = new AdapterChart(getContext(),messageList);
recyclerView.setAdapter(adapterChart);
recyclerView.scrollToPosition(recyclerView.getAdapter().getItemCount()-1);
La respuesta de Roc es de gran ayuda. Me gustaría agregarle un pequeño bloque:
mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
Para desplazarse hacia abajo desde cualquier posición en la vista de reciclador hacia abajo
edittext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
rv.postDelayed(new Runnable() {
@Override
public void run() {
rv.scrollToPosition(rv.getAdapter().getItemCount() - 1);
}
}, 1000);
}
});
Probé un método de
@galex
, funcionó hasta refactorizar.
Así que usé una respuesta de
@yanchenko
y cambié un poco.
Probablemente esto se
onCreateView()
que llamé al desplazamiento desde
onCreateView()
, donde se creó una vista de fragmento (y probablemente no tenía el tamaño correcto).
private fun scrollPhotosToEnd(view: View) {
view.recycler_view.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.recycler_view.viewTreeObserver.removeOnGlobalLayoutListener(this)
} else {
@Suppress("DEPRECATION")
view.recycler_view.viewTreeObserver.removeGlobalOnLayoutListener(this)
}
adapter?.itemCount?.takeIf { it > 0 }?.let {
view.recycler_view.scrollToPosition(it - 1)
}
}
})
}
También puede agregar una verificación de
viewTreeObserver.isAlive
como en
https://.com/a/39001731/2914140
.
Sé que es tarde para responder aquí, aún si alguien quiere saber la solución está por debajo
conversationView.smoothScrollToPosition(conversationView.getAdapter().getItemCount() - 1);
SI tiene un adaptador conectado con recyclerView, simplemente haga esto.
mRecyclerView.smoothScrollToPosition(mRecyclerView.getAdapter().getItemCount());
Simplemente configure
setStackFromEnd=true
o
setReverseLayout=true
para que LLM
setReverseLayout=true
elementos desde el final.
La diferencia entre estos dos es que
setStackFromEnd
configurará la vista para mostrar el último elemento, la dirección de diseño seguirá siendo la misma.
(Por lo tanto, en una vista de reciclador horizontal de izquierda a derecha, se mostrará el último elemento y el desplazamiento hacia la izquierda mostrará los elementos anteriores)
Mientras que
setReverseLayout
cambiará el orden de los elementos agregados por el Adaptador.
El diseño comenzará desde el último elemento, que será el más a la izquierda en una Vista de Reciclador LTR y luego, al desplazarse hacia la derecha, se mostrarán los elementos anteriores.
Muestra:
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
_listView.setLayoutManager(linearLayoutManager);
Consulte la documentation para más detalles.
Solo la respuesta de Ian fue capaz de hacer que mi
RecyclerView
desplazara a una posición específica.
Sin embargo, The
RecyclerView
no pudo desplazarse después cuando utilicé
scrollToPosition()
.
smoothScrollToPosition()
funcionó pero la animación inicial lo hizo demasiado lento cuando la lista era larga.
La razón fue que el oyente no fue eliminado.
Utilicé el siguiente código para eliminar el
ViewTreeObserver
actual y funcionó de
ViewTreeObserver
.
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mRecyclerView.scrollToPosition(mPosition);
mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
Solución para Kotlin :
aplique el siguiente código después de configurar "recyclerView.adapter" o después de "recyclerView.adapter.notifyDataSetChanged ()"
recyclerView.scrollToPosition(recyclerView.adapter.itemCount - 1)
este código te dará la última publicación primero, creo que esta respuesta es útil.
mInstaList=(RecyclerView)findViewById(R.id.insta_list);
mInstaList.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mInstaList.setLayoutManager(layoutManager);
layoutManager.setStackFromEnd(true);
layoutManager.setReverseLayout(true);
class MyLayoutManager extends LinearLayoutManager {
public MyLayoutManager(Context context) {
super(context, LinearLayoutManager.VERTICAL, false);
}
@Override public void smoothScrollToPosition(RecyclerView recyclerView,
final RecyclerView.State state, final int position) {
int fcvip = findFirstCompletelyVisibleItemPosition();
int lcvip = findLastCompletelyVisibleItemPosition();
if (position < fcvip || lcvip < position) {
// scrolling to invisible position
float fcviY = findViewByPosition(fcvip).getY();
float lcviY = findViewByPosition(lcvip).getY();
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
int currentState = RecyclerView.SCROLL_STATE_IDLE;
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (currentState == RecyclerView.SCROLL_STATE_SETTLING
&& newState == RecyclerView.SCROLL_STATE_IDLE) {
// recursive scrolling
smoothScrollToPosition(recyclerView, state, position);
}
currentState = newState;
}
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int fcvip = findFirstCompletelyVisibleItemPosition();
int lcvip = findLastCompletelyVisibleItemPosition();
if ((dy < 0 && fcvip == position) || (dy > 0 && lcvip == position)) {
// stop scrolling
recyclerView.setOnScrollListener(null);
}
}
});
if (position < fcvip) {
// scroll up
recyclerView.smoothScrollBy(0, (int) (fcviY - lcviY));
} else {
// scroll down
recyclerView.smoothScrollBy(0, (int) (lcviY - fcviY));
}
} else {
// scrolling to visible position
float fromY = findViewByPosition(fcvip).getY();
float targetY = findViewByPosition(position).getY();
recyclerView.smoothScrollBy(0, (int) (targetY - fromY));
}
}
}
y
MyLayoutManager layoutManager = new MyLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);
RecyclerView.Adapter adapter = new YourAdapter();
recyclerView.setAdapter(adapter);
recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);
el código anterior funciona, pero no es suave ni genial.