Android ViewPager: muestra la vista previa de la página a la izquierda y a la derecha

107

Estoy usando Android ViewPager. Lo que quiero hacer es mostrar una vista previa de la página tanto a la izquierda como a la derecha. He visto dónde puedo usar un negativo pageMarginpara mostrar una vista previa del lado derecho.

setPageMargin(-100);

¿Hay alguna forma de que pueda mostrar una vista previa del lado izquierdo también? Es básicamente algo similar al widget de galería que estoy buscando.

Brian Boyle
fuente
¡Buena pregunta! Recientemente revisé la fuente y creo que no hay mejor manera si no desea modificar el código src. ¿ setPageMargin(-100)Funciona correctamente?
Macarse
GalleryView hará el trabajo mejor, a menos que esté usando ViewPger con fragmentos.
Ali AlNoaimi
Pude hacer esto usando la vista de galería. lo mismo que viewpager de cualquier manera. no sé por qué la galería está obsoleta
WillingLearner
Desde entonces, esta pregunta se ha tratado ampliamente en la [publicación aquí] [1] [1]: stackoverflow.com/questions/13914609/…
Ben Pearson
Estoy usando Vierpager con fragmentos, ¿puedo usar el mismo enfoque?
asliyanage

Respuestas:

206

Para mostrar la vista previa de las páginas izquierda y derecha, establezca los dos valores siguientes

  1. viewpager.setClipToPadding(false);
  2. viewpager.setPadding(left,0,right,0);

Si necesita espacio entre dos páginas en el visor, agregue

viewpager.setPageMargin(int);
Jiju Induchoodan
fuente
2
Sí, estoy de acuerdo contigo Jiju Induchoodan. Para obtener más información, consulta blog.neteril.org/blog/2013/10/14/… y stackoverflow.com/questions/13914609/…
Sripathi
Genial, es tan simple :) ¿Es posible cambiar el tamaño de las vistas previas en los tamaños derecho e izquierdo en las páginas de cambio de la vista del paginador? Por ejemplo, si el fragmento está desenfocado, su escala será ~ 0.8, pero cuando lo arrastramos al centro, la escala aumentará a 1, y el fragmento anterior de la vista central cambiará la escala a 0.8 cuando salga de la pantalla.
iamthevoid
¡Esto está funcionando! Pero cuando trato de hacer zoom en el diseño del centro, se amplía hacia arriba y hacia abajo. La izquierda y la derecha no son visibles debido al relleno. Consulte la pregunta stackoverflow.com/questions/52710076/…
Anooj Krishnan G
no funciona con viewpager 2
hamiid reza Gholami hace
73

La respuesta de @JijuInduchoodan es perfecta y funciona. Sin embargo, dado que soy relativamente nuevo en Android, me tomó un tiempo entenderlo y configurarlo correctamente. Por lo tanto, estoy publicando esta respuesta para referencia futura y ayudar a cualquier otra persona que esté en mis mismos zapatos.

if (viewPager == null) 
        {

            // Initializing view pager
            viewPager = (ViewPager) findViewById(R.id.vpLookBook);

            // Disable clip to padding
            viewPager.setClipToPadding(false);
            // set padding manually, the more you set the padding the more you see of prev & next page
            viewPager.setPadding(40, 0, 40, 0);
            // sets a margin b/w individual pages to ensure that there is a gap b/w them
            viewPager.setPageMargin(20);
        }

No es necesario establecer ningún ancho para la ViewPager'spágina en el adaptador. No se requiere código adicional para ver la página anterior y siguiente en ViewPager. Sin embargo, si desea agregar un espacio en blanco en la parte superior e inferior de cada página, puede configurar el siguiente código para ViewPager'sel diseño principal de la página secundaria.

android:paddingTop="20dp"
android:paddingBottom="20dp"

ViewPager final

Este será el aspecto final de ViewPager.

Rohan Kandwal
fuente
62

Solución con el nuevo ViewPager2

Hoy en día debería considerar el uso de ViewPager2 que "reemplaza a ViewPager, abordando la mayoría de los puntos débiles de su predecesor" :

  • Basado en RecyclerView
  • Soporte de diseño RTL (de derecha a izquierda)
  • Soporte de orientación vertical
  • Compatibilidad con fragmentos confiables (incluido el manejo de cambios en la colección de fragmentos subyacente)
  • Animaciones de cambio de conjunto de datos (incluido el DiffUtilsoporte)

El resultado

ingrese la descripción de la imagen aquí

El código

En su Actividad / Fragmento, configure ViewPager2:

// MyRecyclerViewAdapter is an standard RecyclerView.Adapter :)
viewPager2.adapter = MyRecyclerViewAdapter() 

// You need to retain one page on each side so that the next and previous items are visible
viewPager2.offscreenPageLimit = 1

// Add a PageTransformer that translates the next and previous items horizontally
// towards the center of the screen, which makes them visible
val nextItemVisiblePx = resources.getDimension(R.dimen.viewpager_next_item_visible)
val currentItemHorizontalMarginPx = resources.getDimension(R.dimen.viewpager_current_item_horizontal_margin)
val pageTranslationX = nextItemVisiblePx + currentItemHorizontalMarginPx
val pageTransformer = ViewPager2.PageTransformer { page: View, position: Float ->
    page.translationX = -pageTranslationX * position
    // Next line scales the item's height. You can remove it if you don't want this effect
    page.scaleY = 1 - (0.25f * abs(position))
    // If you want a fading effect uncomment the next line:
    // page.alpha = 0.25f + (1 - abs(position))
}
viewPager2.setPageTransformer(pageTransformer)

// The ItemDecoration gives the current (centered) item horizontal margin so that
// it doesn't occupy the whole screen width. Without it the items overlap
val itemDecoration = HorizontalMarginItemDecoration(
    context,
    R.dimen.viewpager_current_item_horizontal_margin
)
viewPager2.addItemDecoration(itemDecoration)

Agregue el HorizontalMarginItemDecoration, que es trivial ItemDecoration:

/**
 * Adds margin to the left and right sides of the RecyclerView item.
 * Adapted from https://stackoverflow.com/a/27664023/4034572
 * @param horizontalMarginInDp the margin resource, in dp.
 */
class HorizontalMarginItemDecoration(context: Context, @DimenRes horizontalMarginInDp: Int) :
    RecyclerView.ItemDecoration() {

    private val horizontalMarginInPx: Int =
        context.resources.getDimension(horizontalMarginInDp).toInt()

    override fun getItemOffsets(
        outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
    ) {
        outRect.right = horizontalMarginInPx
        outRect.left = horizontalMarginInPx
    }

}

Agregue las dimensiones que controlan cuánto del elemento anterior / siguiente es visible y el margen horizontal del elemento actual:

<dimen name="viewpager_next_item_visible">26dp</dimen>
<dimen name="viewpager_current_item_horizontal_margin">42dp</dimen>

ingrese la descripción de la imagen aquí

Finalmente agregue el ViewPager2a su diseño:

<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/viewPager"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

Una cosa importante: un ViewPager2elemento debe tener layout_height="match_parent"(de lo contrario, arroja una IllegalStateException), por lo que debe hacer algo como:

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" <-- this!
    app:cardCornerRadius="8dp"
    app:cardUseCompatPadding="true">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="280dp">

        <!-- ... -->

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

Ejemplos de PageTransformer

Google ha agregado una guía sobre ViewPager2 que tiene 2 PageTransformerimplementaciones que puede usar como inspiración: https://developer.android.com/training/animation/screen-slide-2

Acerca del nuevo ViewPager2

Albert Vila Calvo
fuente
El mismo problema en los dispositivos Oreo, el inicio y el final del relleno funcionan como se esperaba en otros dispositivos, pero Oreo después de ViewPager2. PageTransformer resolvió el problema, los rellenos siguen siendo los mismos y tuve que agregarviewpager.setPageTransformer { page, position -> page.translationX = -1 * position }
zgr
Tengo que mover ligeramente la página del buscapersonas para obtener este efecto
Muhammad Saqib
no importa, olvidé agregar esta línea setOffscreenPageLimit(1):)
Muhammad Saqib
Esta es la mejor solución que he encontrado. Funciona perfectamente, pero sí, NO OLVIDE establecer el ancho y la altura del elemento de ViewPager2 en MATCH_PARENT.
khushbu
26

En 2017 tal comportamiento, además, se puede conseguir fácilmente mediante el uso RecyclerViewcon PagerSnapHelper (añadido en la versión 25.1.0 de biblioteca de soporte v7): 

ingrese la descripción de la imagen aquí

Hace algún tiempo necesitaba una función similar a un visor y preparé una pequeña biblioteca:

MetalRecyclerPagerView : puede encontrar todo el código junto con ejemplos allí.

Consiste principalmente en un archivo de clase única: MetalRecyclerViewPager.java (y dos xmls: attrs.xml e ids.xml ).

Espero que ayude a alguien y ahorre algunas horas :)

Alexander Bilchuk
fuente
Fuera de tema, porque a veces solo se necesita un buscapersonas, ¡pero es bueno saberlo! ¡Gracias por compartir!
sud007
Esto es asombroso. Ya tenía toneladas de código auxiliar de RecyclerView. Solo agrego un simple new PagerSnapHelper().attachToRecyclerView(recyclerView)y tengo un ajuste de página.
Steve
9

Si alguien todavía está buscando una solución, había personalizado ViewPage para lograrlo sin usar un margen negativo, encuentre un proyecto de muestra aquí https://github.com/44kksharma/Android-ViewPager-Carousel-UI , debería funcionar en la mayoría de los casos, pero usted todavía puede definir el margen de la página con mPager.setPageMargin(margin in pixel);

44kksharma
fuente
7

Puede hacer esto en un archivo xml, solo use el siguiente código:

 android:clipToPadding="false"
 android:paddingLeft="XX"
 android:paddingRight="XX"

Por ejemplo:

<androidx.viewpager.widget.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:paddingLeft="30dp"
        android:paddingRight="30dp" />

Nota: si necesita espacio entre las páginas, configure el relleno / margen en los fragmentos secundarios

sma6871
fuente
3
Yo voté en contra. lo siento hermano. ¡Funcionó esta vez! Votación a favor de nuevo
shikhar bansal
1

Para aquellos que luchan por tener esto en diferentes pantallas,

mPager.setClipToPadding(false);
DisplayMetrics displayMetrics = new DisplayMetrics();
self.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int paddingToSet = width/4; //set this ratio according to how much of the next and previos screen you want to show.
mPager.setPadding(paddingToSet,0,paddingToSet,0);
Saurabh Verma
fuente
0

Tenga en cuenta que cuando no establece ningún relleno de cero en un visor, la ubicación del efecto de borde del visor se estropea, esto es un error del visor, consulte aquí: error del efecto de borde del visor

Puede deshabilitar el efecto de borde configurando android:overScrollMode="never"el visor, o puede corregir el error con una versión ligeramente modificada de la clase EdgeEffect : Corrección de ViewPagerEdgeEffect

ssynhtn
fuente
-10

Utilice este adaptador de fragmentos y clase para ver el visor en scroll izquierdo y derecho. Agregue las clases necesarias para desplazarse y ver las páginas siguientes.

package com.rmn.viewpager;

import java.util.List;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

/**
 * The <code>PagerAdapter</code> serves the fragments when paging.
 * @author mwho
 */
public class PagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> fragments;
    /**
     * @param fm
     * @param fragments
     */
    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }
    /* (non-Javadoc)
     * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
     */
    @Override
    public Fragment getItem(int position) {
        return this.fragments.get(position);
    }

    /* (non-Javadoc)
     * @see android.support.v4.view.PagerAdapter#getCount()
     */
    @Override
    public int getCount() {
        return this.fragments.size();
    }
}



package com.manishkpr.viewpager;


import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {
    private Context _context;

    public ViewPagerAdapter(Context context, FragmentManager fm) {
        super(fm);  
        _context=context;

        }
    @Override
    public Fragment getItem(int position) {
        Fragment f = new Fragment();
        switch(position){
        case 0:
            f=LayoutOne.newInstance(_context);  
            break;
        case 1:
            f=LayoutTwo.newInstance(_context);  
            break;
        }
        return f;
    }
    @Override
    public int getCount() {
        return 2;
    }

}
Veerababu Medisetti
fuente