Android ViewPager - Mostrar visualização da página à esquerda e à direita


107

Estou usando o Android ViewPager. O que eu quero fazer é mostrar uma prévia da página à esquerda e à direita. Eu vi onde posso usar um negativo pageMarginpara mostrar uma prévia do lado direito.

setPageMargin(-100);

Existe alguma maneira de mostrar uma visualização do lado esquerdo também? É basicamente algo semelhante ao widget da galeria que estou procurando.


Boa pergunta! Verifiquei recentemente o código-fonte e sinto que não há maneira melhor se você não quiser modificar o código src. O setPageMargin(-100)trabalho está correto?
Macarse de

o GalleryView fará o trabalho melhor, a menos que você esteja usando o ViewPger com fragmentos.
Ali AlNoaimi 01 de

Consegui fazer isso usando a visualização da galeria. igual ao viewpager de qualquer forma. não sei por que a galeria foi descontinuada
WillingLearner

Desde então, esta questão foi amplamente abordada em [postar aqui] [1] [1]: stackoverflow.com/questions/13914609/…
Ben Pearson

Estou usando o Vierpager com fragmentos. Posso usar a mesma abordagem?
asliyanage

Respostas:


206

Para mostrar a visualização das páginas esquerda e direita, defina os dois valores a seguir

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

Se precisar de espaço entre duas páginas no viewpager, adicione

viewpager.setPageMargin(int);

2
Sim, concordo com você Jiju Induchoodan .. Para obter mais informações, consulte blog.neteril.org/blog/2013/10/14/… e stackoverflow.com/questions/13914609/…
Sripathi

Legal, é tão simples :) É possível redimensionar as visualizações nos tamanhos direito e esquerdo nas páginas de alternância do pager de visualização? Por exemplo - se o fragmento estiver fora de foco - sua escala será de ~ 0,8, mas quando arrastamos para o centro - a escala aumentará para 1, e o fragmento anterior da visualização do centro mudará para 0,8 quando sair da tela?
iamthevoid

Isso está funcionando! Mas quando tento dar zoom no layout central, ele está ampliando para cima e para baixo. A esquerda e a direita não são visíveis devido ao preenchimento. Consulte a pergunta stackoverflow.com/questions/52710076/…
Anooj Krishnan G

não funciona com viewpager 2
hamiid reza Gholami

73

A resposta de @JijuInduchoodan é perfeita e está funcionando. No entanto, como sou relativamente novo no Android, demorei um pouco para entendê-lo e configurá-lo corretamente. Então, estou postando esta resposta para referência futura e ajudar qualquer pessoa que esteja no mesmo lugar que eu.

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);
        }

Não há necessidade de definir qualquer largura para a ViewPager'spágina no adaptador. Nenhum código adicional é necessário para ver a página anterior e a próxima em ViewPager. No entanto, se você deseja adicionar um espaço em branco na parte superior e inferior de cada página, pode definir o seguinte código para ViewPager'so layout pai da página filha.

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

ViewPager final

Esta será a aparência final do ViewPager.


62

Solução com o novo ViewPager2

Hoje em dia você deve considerar o uso de ViewPager2, que "substitui ViewPager, abordando a maioria dos pontos problemáticos de seu antecessor" :

  • Baseado em RecyclerView
  • Suporte para layout RTL (direita para esquerda)
  • Suporte de orientação vertical
  • Suporte confiável para fragmentos (incluindo manuseio de alterações na coleção de fragmentos subjacente)
  • Animações de mudança de conjunto de dados (incluindo DiffUtilsuporte)

O resultado

insira a descrição da imagem aqui

O código

Em sua atividade / fragmento, configure o 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)

Adicione o HorizontalMarginItemDecoration, que é 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
    }

}

Adicione as dimensões que controlam quanto do item anterior / próximo é visível e a margem horizontal do item atual:

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

insira a descrição da imagem aqui

Por fim, adicione o ViewPager2ao seu layout:

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

Uma coisa importante: um ViewPager2item deve ter layout_height="match_parent"(caso contrário, ele gera uma IllegalStateException), então você deve fazer 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>

Exemplos de PageTransformer

O Google adicionou um guia sobre ViewPager2 que tem 2 PageTransformerimplementações que você pode usar como inspiração: https://developer.android.com/training/animation/screen-slide-2

Sobre o novo ViewPager2


Mesmo problema em dispositivos oreo, o início e o fim do preenchimento funcionam como esperado em outros dispositivos, mas oreo após ViewPager2. O PageTransformer resolveu o problema, os preenchimentos ainda são os mesmos e tive que adicionarviewpager.setPageTransformer { page, position -> page.translationX = -1 * position }
zgr

Tenho que mover um pouco a página do pager de visualização para obter este efeito
Muhammad Saqib

deixa pra lá, esqueci de adicionar esta linha setOffscreenPageLimit(1):)
Muhammad Saqib

Esta é a melhor solução que já encontrei. Funciona perfeitamente, mas sim, NÃO SE ESQUEÇA de definir a largura e altura do item do ViewPager2 como MATCH_PARENT.
khushbu

26

Em 2017 esse tipo de comportamento também pode ser facilmente conseguido usando RecyclerViewcom PagerSnapHelper (adicionado na versão 25.1.0 da biblioteca de suporte v7): 

insira a descrição da imagem aqui

Algum tempo atrás, eu precisava desse recurso semelhante a um visualizador e preparei uma pequena biblioteca:

MetalRecyclerPagerView - você pode encontrar todo o código junto com exemplos lá.

Principalmente, consiste de um único arquivo de classe: MetalRecyclerViewPager.java (e dois xmls: attrs.xml e ids.xml ).

Espero que ajude alguém e economize algumas horas :)


Fora do assunto, porque às vezes apenas o pager é necessário, mas é bom saber! Obrigado por compartilhar!
sud007

Isso é incrível. Eu já tinha toneladas de código auxiliar RecyclerView. Basta adicionar um simples new PagerSnapHelper().attachToRecyclerView(recyclerView)e tenho o ajuste de página.
Steve


7

Você pode fazer isso em um arquivo xml, basta usar o código abaixo:

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

Por exemplo:

<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" />

Observação: se você precisar de espaço entre as páginas, defina preenchimento / margem para fragmentos filhos


3
Eu votei contra. desculpe mano. Funcionou dessa vez !! Melhor votação
shikhar bansal

1

Para aqueles que lutam para ter isso em telas diferentes,

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);

0

Observe que ao definir nenhum preenchimento de zero para um viewpager, o posicionamento do edgeeffect do viewpager é bagunçado, este é um bug do viewpager, veja aqui: bug do viewpager edgeeffect

Você pode desativar o efeito de borda configurando android:overScrollMode="never"para o viewpager ou pode corrigir o bug com uma versão ligeiramente modificada da classe EdgeEffect: ViewPagerEdgeEffect fix


-10

Use este adaptador de fragmento e classe para visualizar o viewpager na esquerda e direita scroll.add classes necessárias para rolar para visualizar as próximas páginas.

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;
    }

}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.