viewholder setadapter recyclerview item how holder custom create android android-recyclerview linearlayoutmanager

android - setadapter - RecyclerView-Desplácese hasta la posición que no funciona cada vez



recyclerview setadapter (7)

Bueno, he encontrado un trabajo alrededor.

Como scrollToPositionWithOffset(position, offset) fue la mejor llamada que tuve, la estoy usando. He probado la salida en varios conjuntos de datos y hasta ahora no he encontrado ninguna inconsistencia. Esperemos que no haya (Pero si alguien encuentra alguno, por favor comente más abajo).

Pero luego está la cuestión de los last 7 Items que el desplazador no puede desplazarse. Para esos artículos desafortunados ahora estoy usando smoothScrollBy(dx, dy) . Pero como solo se puede utilizar si conoce la posición del elemento de desplazamiento, se vuelve un poco complicado. Pero aquí está la solución (en la gist mencionada anteriormente, solo he cambiado la siguiente definición de función).

public void smoothUserScrollTo(final int position) { if (position < 0 || position > getAdapter().getItemCount()) { Log.e(TAG, "An attempt to scroll out of adapter size has been stopped."); return; } if (getLayoutManager() == null) { Log.e(TAG, "Cannot scroll to position a LayoutManager is not set. " + "Call setLayoutManager with a non-null layout."); return; } if (getChildAdapterPosition(getCenterView()) == position) { scrollToView(getCenterView()); return; } stopScroll(); scrollToPosition(position); if (lastScrollPosition == position || position >= getAdapter().getItemCount() - 7) { addOnLayoutChangeListener(new OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { if (left == oldLeft && right == oldRight && top == oldTop && bottom == oldBottom) { if (getChildAdapterPosition(getCenterView()) == position) { // Only remove the listener if/when the centered items is the item we want to scroll to. removeOnLayoutChangeListener(this); scrollToView(getCenterView()); return; } if (position >= 0 && position < getAdapter().getItemCount() - 7) { removeOnLayoutChangeListener(this); updateViews(); scrollToView(getChildAt(0)); } else if (position >= getAdapter().getItemCount() - 7 && position <= getAdapter().getItemCount()){ // Search in the attached items of the RecyclerView for our required item. // You can remove the loop and optimize your code further if you want to, // but I am gonna leave it here as is. It is simple enough :-). int childPosition = 0; for (int i = 0; i < getChildCount(); i++) { childPosition = getChildAdapterPosition(getChildAt(i)); if (childPosition == position) { updateViews(); scrollToView(getChildAt(i)); break; } // Since we couldn''t find the item in attached items. // Scroll to the last attached item (It''ll dettach and attach // necessary items). So we can scroll once the view is stable again. if (i == getChildCount() - 2) { scrollToView(getChildAt(i)); } } } } } }); } lastScrollPosition = position; }

Nota: Solo estoy usando smoothScrollBy(dx, dy) para los últimos 7 artículos. También cualquier cambio son bienvenidos.

He implementado un RecyclerView desplazable horizontal. Mi RecyclerView utiliza un LinearLayoutManager , y el problema al que me estoy enfrentando es que cuando intento usar scrollToPosition(position) o smoothScrollToPosition(position) o desde LinearLayoutManager smoothScrollToPosition(position) de LinearLayoutManager . Tampoco me funciona. Una llamada de desplazamiento no se desplaza a la ubicación deseada o no invoca OnScrollListener .

Hasta ahora he probado tantas combinaciones diferentes de código que no puedo publicarlas todas aquí. El siguiente es el que funciona para mí (pero solo parcialmente):

public void smoothUserScrollTo(final int position) { if (position < 0 || position > getAdapter().getItemCount()) { Log.e(TAG, "An attempt to scroll out of adapter size has been stopped."); return; } if (getLayoutManager() == null) { Log.e(TAG, "Cannot scroll to position a LayoutManager is not set. " + "Call setLayoutManager with a non-null layout."); return; } if (getChildAdapterPosition(getCenterView()) == position) { return; } stopScroll(); scrollToPosition(position); if (lastScrollPosition == position) { addOnLayoutChangeListener(new OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { if (left == oldLeft && right == oldRight && top == oldTop && bottom == oldBottom) { removeOnLayoutChangeListener(this); updateViews(); // removing the following line causes a position - 3 effect. scrollToView(getChildAt(0)); } } }); } lastScrollPosition = position; } @Override public void scrollToPosition(int position) { if (position < 0 || position > getAdapter().getItemCount()) { Log.e(TAG, "An attempt to scroll out of adapter size has been stopped."); return; } if (getLayoutManager() == null) { Log.e(TAG, "Cannot scroll to position a LayoutManager is not set. " + "Call setLayoutManager with a non-null layout."); return; } // stopScroll(); ((LinearLayoutManager) getLayoutManager()).scrollToPositionWithOffset(position, 0); // getLayoutManager().scrollToPosition(position); }

Opté por scrollToPositionWithOffset() debido a this pero el caso quizás sea diferente, ya que uso un LinearLayoutManager en lugar de GridLayoutManager. Pero la solución también funciona para mí, pero como dije anteriormente solo parcialmente.

  • Cuando la llamada a desplazarse es de la posición 0 a tamaño total, el desplazamiento 7 funciona como un amuleto.
  • Cuando el desplazamiento es de totalSize - 7 a totalSize - 3, la primera vez solo me desplazo hasta el séptimo último elemento de la lista. La segunda vez sin embargo puedo desplazarme bien
  • Cuando me desplazo de totalSize - 3 a totalSize, empiezo a tener un comportamiento inesperado.

Si alguien ha encontrado un trabajo alrededor lo apreciaría. Aquí está la gist de mi código de ReyclerView personalizado.


Ninguno de los métodos parece estar funcionando para mí. Sólo la siguiente línea de código trabajó

((LinearLayoutManager)mRecyclerView.getLayoutManager()).scrollToPositionWithOffset(adapter.currentPosition(),200);

El segundo parámetro se refiere al desplazamiento, que en realidad es la distancia (en píxeles) entre el borde inicial de la vista del elemento y el borde inicial del RecyclerView. Lo he suministrado con un valor constante para que los elementos superiores también sean visibles.

Verifique más referencias here


Resulta que estaba teniendo un problema similar hasta que utilicé

myRecyclerview.scrollToPosition(objectlist.size()-1)

Siempre se mantendría en la parte superior cuando solo se agregue el tamaño de la lista de objetos. Esto fue hasta que decidí establecer el tamaño igual a una variable. Una vez más, eso no funcionó. Entonces asumí que tal vez estaba manejando una excepción externa sin decírmelo. Así que lo resté por 1. Luego funcionó.


Tenía el mismo problema. Mi problema fue que recargué la vista con datos en una tarea asíncrona, después de que intenté desplazarme. Desde onPostExecute ofc solucionó este problema. Un retraso solucionó este problema también, porque cuando se ejecutó el desplazamiento, la lista ya se había rellenado.


Tuve el mismo problema al crear un adaptador cíclico / circular, donde solo podía desplazarme hacia abajo pero no hacia arriba, considerando que la posición se inicializa a 0 . Primero consideré usar el enfoque de Robert, pero era demasiado poco confiable ya que el Handler solo disparó una vez, y si tuve mala suerte, la posición no se podría inicializar en algunos casos.

Para resolver esto, creo un intervalo observable que verifica cada XXX la cantidad de tiempo para ver si la inicialización se realizó correctamente y luego se deshace de ella. Este enfoque funcionó muy confiablemente para mi caso de uso.

private fun initialisePositionToAllowBidirectionalScrolling(layoutManager: LinearLayoutManager, realItemCount: Int) { val compositeDisposable = CompositeDisposable() // Added here for clarity, make this into a private global variable and clear in onDetach()/onPause() in case auto-disposal wouldn''t ever occur here val initPosition = realItemCount * 1000 Observable.interval(INIT_DELAY_MS, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe ({ if (layoutManager.findFirstVisibleItemPosition() == 0) { layoutManager.scrollToPositionWithOffset(initPosition, 0) if (layoutManager.findFirstCompletelyVisibleItemPosition() == initPosition) { Timber.d("Adapter initialised, setting position to $initPosition and disposing interval subscription!") compositeDisposable.clear() } } }, { Timber.e("Failed to initialise position!/n$it") compositeDisposable.clear() }).let { compositeDisposable.add(it) } }


Tuve el mismo problema hace algunas semanas y encontré una solución realmente mala para resolverlo. Tuvo que usar un postDelayed con 200-300ms.

new Handler().postDelayed(new Runnable() { @Override public void run() { yourList.scrollToPosition(position); } }, 200);

Si encontraste una solución mejor, por favor házmelo saber! ¡Buena suerte!


Utilizo la siguiente solución para hacer que el elemento seleccionado en la vista de reciclador sea visible después de que se recargue la vista de reciclador (cambio de orientación, etc.). Anula LinearLayoutManager y usa onSaveInstanceState para guardar la posición actual del reciclador. Luego, en onRestoreInstanceState se restaura la posición guardada. Finalmente , en onLayoutCompleted , scrollToPosition (mRecyclerPosition) se usa para hacer visible nuevamente la posición del reciclador previamente seleccionada, pero como Robert Banyai declaró, para que funcione de manera confiable, se debe insertar un cierto retraso. Supongo que es necesario proporcionar suficiente tiempo para que el adaptador cargue los datos antes de llamar a scrollToPosition.

private class MyLayoutManager extends LinearLayoutManager{ private boolean isRestored; public MyLayoutManager(Context context) { super(context); } public MyLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public MyLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public void onLayoutCompleted(RecyclerView.State state) { super.onLayoutCompleted(state); if(isRestored && mRecyclerPosition >-1) { Handler handler=new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { MyLayoutManager.this.scrollToPosition(mRecyclerPosition); } },200); } isRestored=false; } @Override public Parcelable onSaveInstanceState() { Parcelable savedInstanceState = super.onSaveInstanceState(); Bundle bundle=new Bundle(); bundle.putParcelable("saved_state",savedInstanceState); bundle.putInt("position", mRecyclerPosition); return bundle; } @Override public void onRestoreInstanceState(Parcelable state) { Parcelable savedState = ((Bundle)state).getParcelable("saved_state"); mRecyclerPosition = ((Bundle)state).getInt("position",-1); isRestored=true; super.onRestoreInstanceState(savedState); } }