recyclerview java android scroll android-recyclerview

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.