Estoy tratando de hacer un carrusel de vista de aquí el uso de RecyclerView, quiero que el elemento a ajustar en el medio de la pantalla cuando el desplazamiento, un elemento a la vez. He intentado usar recyclerView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING);

pero la vista es todavía desplazamiento sin problemas, también he probado a poner en práctica mi propia lógica mediante los botones de desplazamiento escucha así:

recyclerView.setOnScrollListener(new OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    Log.v("Offset ", recyclerView.getWidth() + "");
                    if (newState == 0) {
                        try {
                               recyclerView.smoothScrollToPosition(layoutManager.findLastVisibleItemPosition());
                                recyclerView.scrollBy(20,0);
                            if (layoutManager.findLastVisibleItemPosition() >= recyclerView.getAdapter().getItemCount() - 1) {
                                Beam refresh = new Beam();
                                refresh.execute(createUrl());
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

La desliza el dedo de derecha a izquierda está funcionando bien ahora, pero no la otra manera alrededor, lo que me estoy perdiendo aquí ?

InformationsquelleAutor Ahmed Awad | 2015-03-18

7 Comentarios

  1. 125

    Con LinearSnapHelper, este de ahora es muy fácil.

    Todo lo que necesitas hacer es esto:

    SnapHelper helper = new LinearSnapHelper();
    helper.attachToRecyclerView(recyclerView);

    Actualización

    Disponible desde 25.1.0, PagerSnapHelper puede ayudar a lograr ViewPager como efecto. Usarlo como te gustaría utilizar el LinearSnapHelper.

    Viejo solución:

    Si usted desea que se comportan similar a la ViewPager, intente esto en su lugar:

    LinearSnapHelper snapHelper = new LinearSnapHelper() {
        @Override
        public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
            View centerView = findSnapView(layoutManager);
            if (centerView == null) 
                return RecyclerView.NO_POSITION;
    
            int position = layoutManager.getPosition(centerView);
            int targetPosition = -1;
            if (layoutManager.canScrollHorizontally()) {
                if (velocityX < 0) {
                    targetPosition = position - 1;
                } else {
                    targetPosition = position + 1;
                }
            }
    
            if (layoutManager.canScrollVertically()) {
                if (velocityY < 0) {
                    targetPosition = position - 1;
                } else {
                    targetPosition = position + 1;
                }
            }
    
            final int firstItem = 0;
            final int lastItem = layoutManager.getItemCount() - 1;
            targetPosition = Math.min(lastItem, Math.max(targetPosition, firstItem));
            return targetPosition;
        }
    };
    snapHelper.attachToRecyclerView(recyclerView);

    La implementación anterior sólo devuelve la posición al lado del elemento actual (en el centro) en función de la dirección de la velocidad, independientemente de la magnitud.

    La anterior es una primera parte de la solución incluida en la Biblioteca de Compatibilidad de la versión 24.2.0.
    Lo que significa que usted tiene que agregar esto a tu aplicación del módulo de build.gradle o actualización.

    compile "com.android.support:recyclerview-v7:24.2.0"
    • Este no me funciona (pero la solución por @Albert Vila Calvo hizo). Han implementado? Se supone que vamos a reemplazar los métodos de ello? Yo creo que la clase debe hacer todo el trabajo fuera de la caja
    • Sí, de ahí la respuesta. No he probado a fondo, sin embargo. Para ser claros, esto lo hice con una horizontal LinearLayoutManager donde las vistas eran regulares en tamaño. Nada más, pero el fragmento de código anterior es necesario.
    • disculpas, he entendido lo que quería decir y se han hecho algunas editar reconociendo que, por favor hacer comentarios. Esta es una solución alternativa con la LinearSnapHelper.
    • Esto funcionó muy bien para mí. @galaxigirl la anulación de este método ayuda a que el lineal complemento auxiliar de otra manera va a ajustar a la más cercana elemento cuando el desplazamiento se está asentando, no exactamente solo el elemento siguiente o anterior. Muchas gracias por esta, razzledazzle
    • +++ Me dan más puntos si pudiera. Esto me ayudó a salir de horas de tratar de cómo hacerlo. 🙂
    • Dios los Bendiga!!
    • Me gustaría marcar esto para la mejor solución para señalar PagerSnapHelper
    • Exactamente el tipo de comportamiento que yo estaba buscando y le tomó sólo 2 líneas de código! Gracias! @razzledazzle
    • ¿qué es findSnapView? cómo usar el código anterior?

  2. 56

    Google I/O 2019 Actualización:

    ViewPager2 está aquí!

    Google acaba de anunciar en la charla ‘¿Qué hay de Nuevo en Android’ (aka ‘El Android keynote’) que están trabajando en un nuevo ViewPager basado en RecyclerView!

    De las diapositivas:

    Como ViewPager, pero mejor

    • Fácil migración de ViewPager
    • Basado en RecyclerView
    • De derecha a Izquierda, de modo de apoyar
    • Permite vertical de paginación
    • Mejorado conjunto de datos de las notificaciones de cambio de

    Usted puede revisar la versión más reciente aquí y las notas de la versión aquí.

    Opinión Personal: yo creo que este no es realmente necesario, además. Hace poco he tenido un montón de problemas con el PagerSnapHelper oscilación a la izquierda a la derecha indefinidamente – ver el billete que he abierto.


    Nueva respuesta (2016):

    Ahora puedes utilizar un SnapHelper.

    Si quieres un alineada en el centro de ajuste comportamiento similar a ViewPager, a continuación, utilizar un PagerSnapHelper:

    SnapHelper snapHelper = new PagerSnapHelper();
    snapHelper.attachToRecyclerView(recyclerView);

    También hay un LinearSnapHelper. Yo lo he probado y si se aventura con la energía, entonces se desplaza 2 puntos con 1 fling. Personalmente no me gusta, pero acabo de decidir por sí mismo – tratando de solo tarda unos segundos.


    Respuesta Original (2016):

    Después de muchos horas tratando de 3 diferentes soluciones que se encuentran aquí, ASÍ que finalmente he desarrollado una solución que imita muy de cerca el comportamiento encontrado en un ViewPager.

    La solución está basada en el @eDizzle solución, que creo que he mejorado lo suficiente como para decir que funciona casi como un ViewPager.

    Importante: mi RecyclerView elementos anchura es exactamente el mismo que el de la pantalla. No he probado con otros tamaños. También lo uso con una horizontal LinearLayoutManager. Creo que será necesario adaptar el código si desea desplazamiento vertical.

    Aquí tienes el código:

    public class SnappyRecyclerView extends RecyclerView {
    //Use it with a horizontal LinearLayoutManager
    //Based on https://stackoverflow.com/a/29171652/4034572
    public SnappyRecyclerView(Context context) {
    super(context);
    }
    public SnappyRecyclerView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    }
    public SnappyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    }
    @Override
    public boolean fling(int velocityX, int velocityY) {
    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();
    int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
    //views on the screen
    int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
    View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition);
    int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
    View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition);
    //distance we need to scroll
    int leftMargin = (screenWidth - lastView.getWidth()) / 2;
    int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth();
    int leftEdge = lastView.getLeft();
    int rightEdge = firstView.getRight();
    int scrollDistanceLeft = leftEdge - leftMargin;
    int scrollDistanceRight = rightMargin - rightEdge;
    if (Math.abs(velocityX) < 1000) {
    //The fling is slow -> stay at the current page if we are less than half through,
    //or go to the next page if more than half through
    if (leftEdge > screenWidth / 2) {
    //go to next page
    smoothScrollBy(-scrollDistanceRight, 0);
    } else if (rightEdge < screenWidth / 2) {
    //go to next page
    smoothScrollBy(scrollDistanceLeft, 0);
    } else {
    //stay at current page
    if (velocityX > 0) {
    smoothScrollBy(-scrollDistanceRight, 0);
    } else {
    smoothScrollBy(scrollDistanceLeft, 0);
    }
    }
    return true;
    } else {
    //The fling is fast -> go to next page
    if (velocityX > 0) {
    smoothScrollBy(scrollDistanceLeft, 0);
    } else {
    smoothScrollBy(-scrollDistanceRight, 0);
    }
    return true;
    }
    }
    @Override
    public void onScrollStateChanged(int state) {
    super.onScrollStateChanged(state);
    //If you tap on the phone while the RecyclerView is scrolling it will stop in the middle.
    //This code fixes this. This code is not strictly necessary but it improves the behaviour.
    if (state == SCROLL_STATE_IDLE) {
    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();
    int screenWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
    //views on the screen
    int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
    View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition);
    int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
    View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition);
    //distance we need to scroll
    int leftMargin = (screenWidth - lastView.getWidth()) / 2;
    int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth();
    int leftEdge = lastView.getLeft();
    int rightEdge = firstView.getRight();
    int scrollDistanceLeft = leftEdge - leftMargin;
    int scrollDistanceRight = rightMargin - rightEdge;
    if (leftEdge > screenWidth / 2) {
    smoothScrollBy(-scrollDistanceRight, 0);
    } else if (rightEdge < screenWidth / 2) {
    smoothScrollBy(scrollDistanceLeft, 0);
    }
    }
    }
    }

    Disfrutar!

    • Buena captura el onScrollStateChanged(); de lo contrario, un pequeño fallo está presente si nos deslizar lentamente la RecyclerView. Gracias!
    • Para apoyar a los márgenes (android:layout_marginStart=»16dp») he probado con int screenwidth = getWidth(); y parece que funciona.
    • Increíble solución!!!
    • AWESOOOMMEEEEEEEEE
    • ¿Cómo funciona esto con la baja de la API? Desde RecyclerView necesita ser utilizado con android.support.v7.widget.RecyclerView ser adaptable para el bajo de la API y este método requiere el uso de su propia etiqueta xml.
    • su solución es de gran tuve éxito con la nueva LinearSnapHelper clase. Han implementado?
    • no, no he trató de LinearSnapHelper todavía. Acabo de actualizar la respuesta para que la gente sepa acerca de la solución oficial. Mi solución funciona sin ningún problema en mi aplicación.
    • Traté de LinearSnapHelper. LinearSnapHelper trabaja con una barra de desplazamiento. Se desplaza y se ajusta en base a la gravedad y la aventura de la velocidad. Mayor es la velocidad más páginas se desplaza. No la recomendaría para un ViewPager de comportamiento similar.
    • hizo algunas modificaciones para que el comportamiento, compruebe por favor stackoverflow.com/a/39036351/4803633 y proporcionar retroalimentación.
    • Me gusta la solución. Pero, el objetivo de la posición del elemento se basa en el tiempo que el arrastre. Si la resistencia es mayor que la de targetPosition es la posición +/- 2.
    • para apoyar una inversión de diseño de orden int lastVisibleItemPosition = linearLayoutManager.getReverseLayout() ? linearLayoutManager.findFirstVisibleItemPosition() : linearLayoutManager.findLastVisibleItemPosition(); View lastView = linearLayoutManager.findViewByPosition(lastVisibleItemPosition); int firstVisibleItemPosition = linearLayoutManager.getReverseLayout() ? linearLayoutManager.findLastVisibleItemPosition() : linearLayoutManager.findFirstVisibleItemPosition(); View firstView = linearLayoutManager.findViewByPosition(firstVisibleItemPosition);
    • He probado el SnapHelper y trabajó como un ViewPager (exactamente lo que yo quería) con sólo 2 líneas de código !!! SnapHelper snapHelper = new PagerSnapHelper(); snapHelper.attachToRecyclerView(mRecyclerView);
    • Trabajó como un encanto.Gracias
    • Interfaz de usuario alineados sobre la rotación del teléfono.
    • limpiar cosas, buen trabajo
    • ¿Cómo puedo lograr el mismo para el desplazamiento vertical de reciclado de vista ?
    • así que ¿cómo puedo obtener el elemento actual para que?

  3. 38

    Si el objetivo es hacer que el RecyclerView imitar el comportamiento de ViewPager hay bastante fácil enfoque

    RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
    LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
    SnapHelper snapHelper = new PagerSnapHelper();
    recyclerView.setLayoutManager(layoutManager);
    snapHelper.attachToRecyclerView(mRecyclerView);

    Mediante PagerSnapHelper usted puede obtener el comportamiento como ViewPager

    • Estoy usando LinearSnapHelper en lugar de PagerSnapHelper y funciona para mí
    • el efecto es totalmente diferente!
    • Sí, no hay ningún complemento efecto en LinearSnapHelper
    • este palos el elemento en la vista permite scrolable
    • Traté de LinearSnapHelper, y se ajusta a un medio punto. PagerSnapHelper impide desplazarse con facilidad (al menos, una lista de imágenes).
    • me puede decir cómo hacer esto, un elemento en cente totalmente visibles y los elementos secundarios son la mitad visible?

  4. 30

    Necesita utilizar findFirstVisibleItemPosition para ir en la dirección opuesta. Y para la detección de la dirección en la que el pase estaba en, usted necesita para obtener la aventura de la velocidad o el cambio en x. Me acerqué a este problema desde un ángulo ligeramente diferente de la que tiene.

    Crear una nueva clase que extienda la RecyclerView de la clase y, a continuación, reemplace RecyclerView del fling método así:

    @Override
    public boolean fling(int velocityX, int velocityY) {
    LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();
    //these four variables identify the views you see on screen.
    int lastVisibleView = linearLayoutManager.findLastVisibleItemPosition();
    int firstVisibleView = linearLayoutManager.findFirstVisibleItemPosition();
    View firstView = linearLayoutManager.findViewByPosition(firstVisibleView);
    View lastView = linearLayoutManager.findViewByPosition(lastVisibleView);
    //these variables get the distance you need to scroll in order to center your views.
    //my views have variable sizes, so I need to calculate side margins separately.     
    //note the subtle difference in how right and left margins are calculated, as well as
    //the resulting scroll distances.
    int leftMargin = (screenWidth - lastView.getWidth()) / 2;
    int rightMargin = (screenWidth - firstView.getWidth()) / 2 + firstView.getWidth();
    int leftEdge = lastView.getLeft();
    int rightEdge = firstView.getRight();
    int scrollDistanceLeft = leftEdge - leftMargin;
    int scrollDistanceRight = rightMargin - rightEdge;
    //if(user swipes to the left) 
    if(velocityX > 0) smoothScrollBy(scrollDistanceLeft, 0);
    else smoothScrollBy(-scrollDistanceRight, 0);
    return true;
    }
    • Donde se screenWidth definido?
    • Oops! Buena pregunta. Es una variable I que figuran en otras partes de la clase. Es el ancho de la pantalla del dispositivo en píxeles, no de la densidad de píxeles, ya que el smoothScrollBy método requiere el número de píxeles que desea desplazarse.
    • Usted puede cambiar a getWidth() (recyclerview.getWidth()) en lugar de screenWidth. screenWidth no funciona correctamente cuando RecyclerView es más pequeña que la pantalla de ancho.
    • Traté de extender RecyclerView pero me estoy poniendo de Error de «inflar clase personalizada RecyclerView». Puede usted ayudar? Gracias
    • Usted podría querer buscar que en la otra pregunta de alimentación. Es bastante fuera de alcance con la pregunta inicial aquí.
    • usted tiene que crear todos los tres constructores de coincidencia super clase.

  5. 2

    Mi solución:

    /**
    * Horizontal linear layout manager whose smoothScrollToPosition() centers
    * on the target item
    */
    class ItemLayoutManager extends LinearLayoutManager {
    private int centeredItemOffset;
    public ItemLayoutManager(Context context) {
    super(context, LinearLayoutManager.HORIZONTAL, false);
    }
    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
    LinearSmoothScroller linearSmoothScroller = new Scroller(recyclerView.getContext());
    linearSmoothScroller.setTargetPosition(position);
    startSmoothScroll(linearSmoothScroller);
    }
    public void setCenteredItemOffset(int centeredItemOffset) {
    this.centeredItemOffset = centeredItemOffset;
    }
    /**
    * ********** Inner Classes **********
    */
    private class Scroller extends LinearSmoothScroller {
    public Scroller(Context context) {
    super(context);
    }
    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
    return ItemLayoutManager.this.computeScrollVectorForPosition(targetPosition);
    }
    @Override
    public int calculateDxToMakeVisible(View view, int snapPreference) {
    return super.calculateDxToMakeVisible(view, SNAP_TO_START) + centeredItemOffset;
    }
    }
    }

    Les paso este gestor de diseño para la RecycledView y establecer el desplazamiento requerido para productos del centro. Todos mis artículos tienen la misma anchura de manera constante desplazamiento es aceptar

  6. 1

    Acaba de agregar padding y margin a recyclerView y recyclerView item:

    recyclerView elemento:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parentLayout"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_marginLeft="8dp" <!-- here -->
    android:layout_marginRight="8dp" <!-- here  -->
    android:layout_width="match_parent"
    android:layout_height="200dp">
    <!-- child views -->
    </RelativeLayout>

    recyclerView:

    <androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="8dp" <!-- here -->
    android:paddingRight="8dp" <!-- here -->
    android:clipToPadding="false" <!-- important!-->
    android:scrollbars="none" />

    y establecer PagerSnapHelper :

    int displayWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
    parentLayout.getLayoutParams().width = displayWidth - Utils.dpToPx(16) * 4;
    SnapHelper snapHelper = new PagerSnapHelper();
    snapHelper.attachToRecyclerView(recyclerView);

    dp px:

    public static int dpToPx(int dp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    }

    resultado:

    RecyclerView de desplazamiento horizontal complemento en el centro

    • Es allí una manera de lograr la variable de relleno entre los elementos? como si la primera y la última carta que no deben estar centrados para mostrar más de los siguiente/anterior tarjetas vs el intermedio de tarjetas de estar centrado?
  7. 0

    PagerSnapHelper no funciona con GridLayoutManager con spanCount > 1, así que mi solución en este caso es:

    class GridPagerSnapHelper : PagerSnapHelper() {
    override fun findTargetSnapPosition(layoutManager: RecyclerView.LayoutManager?, velocityX: Int, velocityY: Int): Int {
    val forwardDirection = if (layoutManager?.canScrollHorizontally() == true) {
    velocityX > 0
    } else {
    velocityY > 0
    }
    val centerPosition = super.findTargetSnapPosition(layoutManager, velocityX, velocityY)
    return centerPosition +
    if (forwardDirection) (layoutManager as GridLayoutManager).spanCount - 1 else 0
    }
    }

Dejar respuesta

Please enter your comment!
Please enter your name here