RecyclerView smoothDesplácese hasta la posición en el centro. androide

4 minutos de lectura

Avatar de usuario de Stan Malcolm
stan malcolm

Estoy usando un administrador de diseño horizontal para mi RecyclerView. necesito hacer RecyclerView de la siguiente manera: cuando haga clic en algún elemento, haga un desplazamiento suave hasta esa posición y coloque ese elemento en el centro de RecyclerView (si es posible, por ejemplo, 10 artículo de 20).

Entonces, no tengo ningún problema con smoothScrollToPosition()pero cómo poner el artículo que en el centro de RecyclerView???

¡Gracias!

avatar de usuario de user3680200
usuario3680200

Si es posible.

Al implementar RecyclerView.SmoothScrollermétodo de onTargetFound(View, State, Action).

/**
 * Called when the target position is laid out. This is the last callback SmoothScroller
 * will receive and it should update the provided {@link Action} to define the scroll
 * details towards the target view.
 * @param targetView    The view element which render the target position.
 * @param state         Transient state of RecyclerView
 * @param action        Action instance that you should update to define final scroll action
 *                      towards the targetView
 */
abstract protected void onTargetFound(View targetView, State state, Action action);

Específicamente en LinearLayoutManager con LinearSmoothScroller:

public class CenterLayoutManager extends LinearLayoutManager {

    public CenterLayoutManager(Context context) {
        super(context);
    }

    public CenterLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public CenterLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private static class CenterSmoothScroller extends LinearSmoothScroller {

        CenterSmoothScroller(Context context) {
            super(context);
        }

        @Override
        public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
            return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
        }
    }
}

  • extends LinearSmoothScroller debe anular computeScrollVectorForPosition()

    – Ninja

    27 de diciembre de 2016 a las 7:02

  • funcionó impecable

    – Eliseo Ocampos

    21 de abril de 2017 a las 17:11

  • Perfecto, para los demas solo llamas recyclerView.smoothScrollToPosition(position); y no olvide configurar el administrador de diseño recyclerView.setLayoutManager(layoutManager);

    – Pete

    9 de junio de 2017 a las 15:58

  • Donde es eso onTargetFound() función implementada?

    – Los errores suceden

    24 de agosto de 2018 a las 11:05

  • Pero no entendí exactamente por qué mencionaste sobre este método. onTargetFound() ?

    – Sirop4ik

    31 de octubre de 2018 a las 8:55

Avatar de usuario de 王能
王 能

Mejoras a la respuesta – no hay necesidad de anular el LinearLayoutManager

De la respuesta anterior:

public class CenterSmoothScroller extends LinearSmoothScroller {

    public CenterSmoothScroller(Context context) {
        super(context);
    }

    @Override
    public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
        return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
    }
}

Aquí cómo usarlo:

RecyclerView.LayoutManager lm = new GridLayoutManager(...): // or whatever layout manager you need

...

RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());

smoothScroller.setTargetPosition(position);

lm.startSmoothScroll(smoothScroller);

  • Para otros que están confundidos como yo, CenterSmoothScroller es una clase que se encuentra en la respuesta aceptada.

    – rjr-aplicaciones

    14 de febrero de 2019 a las 23:20


  • ¡Aleluya! Pasó medio día probando un montón de formas complicadas de hacer esto y su solución funciona perfectamente. ¡Gracias!

    – mjp66

    18 de marzo de 2020 a las 23:25

  • ¿Cómo obtendré la posición mientras declaro la vista del reciclador? Necesito colocar el elemento en el centro mientras el usuario desplaza el elemento usando D-Pad. @usuario8944115

    – Aravind

    28 de abril de 2020 a las 7:31


  • ¡¡esto funcionó a las mil maravillas!! gracias, si no encuentra la clase, tal vez necesite actualizar sus dependencias, está bajo androidx.recyclerview.widget.LinearSmoothScroller

    – Javier

    2 de julio de 2021 a las 9:46


  • Es una solución correcta y fácil. Gracias

    – Trung Đoan

    25 oct 2021 a las 5:30

En caso de que alguien necesite el Equivalente de Kotlin de la clase en la respuesta aceptada.

class CenterLayoutManager : LinearLayoutManager {
    constructor(context: Context) : super(context)
    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State, position: Int) {
        val centerSmoothScroller = CenterSmoothScroller(recyclerView.context)
        centerSmoothScroller.targetPosition = position
        startSmoothScroll(centerSmoothScroller)
    }

    private class CenterSmoothScroller(context: Context) : LinearSmoothScroller(context) {
        override fun calculateDtToFit(viewStart: Int, viewEnd: Int, boxStart: Int, boxEnd: Int, snapPreference: Int): Int = (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2)
    }
}

avatar de usuario de furkanbzkurt
furkanbzkurt

Según la respuesta de @Boda, si desea controlar la velocidad de desplazamiento suave (para una mejor animación), puede usar lo siguiente:

class CenterLayoutManager : LinearLayoutManager {
    constructor(context: Context) : super(context)
    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(
        context,
        orientation,
        reverseLayout
    )

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
        context,
        attrs,
        defStyleAttr,
        defStyleRes
    )

    override fun smoothScrollToPosition(
        recyclerView: RecyclerView,
        state: RecyclerView.State,
        position: Int
    ) {
        val centerSmoothScroller = CenterSmoothScroller(recyclerView.context)
        centerSmoothScroller.targetPosition = position
        startSmoothScroll(centerSmoothScroller)
    }

    private class CenterSmoothScroller(context: Context) : LinearSmoothScroller(context) {
        override fun calculateDtToFit(
            viewStart: Int,
            viewEnd: Int,
            boxStart: Int,
            boxEnd: Int,
            snapPreference: Int
        ): Int = (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2)

        override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi
        }
    }

    companion object {
        // This number controls the speed of smooth scroll
        private const val MILLISECONDS_PER_INCH = 150f
    }
}

Uso:

recyclerView.layoutManager = CenterLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
recyclerView.smoothScrollToPosition(selectedPosition)

desde ahora (febrero de 2019), podría usar fácilmente este código en ListView

(ListView)word_list_view.smoothScrollToPositionFromTop(your_item_index, center_position.y);

RecyclerView no verificado, supongo que sería lo mismo.

  • No disponible para RecyclerView

    – tagy22

    18 de diciembre de 2019 a las 13:42

  • No disponible para RecyclerView

    – tagy22

    18 de diciembre de 2019 a las 13:42

¿Ha sido útil esta solución?