ViewPager avec les limites de la page précédente et suivante

144

Je conçois une vue avec plusieurs pages. Je veux que les bords des pages précédentes et suivantes soient affichés comme ci-dessous et implémenter un balayage à 2 doigts pour basculer entre les pages.

entrez la description de l'image ici

J'ai essayé d'utiliser ViewPageravec une marge de page négative comme suggéré ici, mais cela ne montre que l'un des bords de l'écran, pas les deux simultanément.

Sinon, est-il possible de positionner une partie de ma vue à l'extérieur de l'écran, puis de l'animer en lui donnant un ViewPagereffet de type.

Comment dois-je m'y prendre? Merci !

Gaurav Arora
la source
"montre seulement un des bords sur l'écran, pas les deux simultanément." Êtes-vous à la page 0 et vous ne voyez qu'une partie de la page 1? Vous devez peut-être utiliser un pager circulaire, par exemple, puis mettre votre page toujours en position «médiane». Voir cet article et le commentaire: stackoverflow.com/a/8304474/1851478
logray

Réponses:

100

Me citant d' un article de blog sur ce sujet :

La troisième approche vient de Dave Smith, co-auteur du célèbre livre Android Recipes. Il est allé dans une direction très différente, en utilisant un conteneur personnalisé qui désactivait le découpage des enfants pour afficher plus d'une page à la fois.

Son exemple de code publié montre le tout en action. Son conteneur ( com.example.pagercontainer.PagerContainer) encapsule le ViewPageret s'appelle setClipChildren(false);sur lui-même, donc même si le ViewPagerest concentré sur une page sélectionnée, les autres pages qui ont des coordonnées au-delà des ViewPagerlimites sont toujours visibles, tant qu'elles s'inscrivent dans le PagerContainer. En dimensionnant le ViewPagerpour qu'il soit plus petit que le PagerContainer, le ViewPagerpeut dimensionner ses pages à cette taille, laissant de la place pour que d'autres pages soient vues. PagerContainer, cependant, doit aider un peu avec les événements tactiles, car ViewPageril ne traitera que les événements de balayage sur ses propres limites visibles, en ignorant les pages visibles sur les côtés.

entrez la description de l'image ici

CommonsWare
la source
1
en utilisant cela, je suis en mesure d'afficher une partie de la page précédente et suivante comme indiqué dans l'image ci-dessus, mais maintenant je ne veux pas afficher des bords nets sur les images.Je veux qu'elles se brouillent vers les bords ... veuillez me guider sur la façon de J'utilise z-index pour obtenir la même chose
Shruti
2
@Shruti - ajoutez simplement une image de superposition avec l'effet souhaité
Daniel L.
2
Je fais la même chose mais cela désactive l'effet de sur-défilement pour le dernier élément. Des pistes à ce sujet?
Swayam
1
@CommonsWare: Monsieur, j'ai essayé votre solution! Cela a plutôt bien fonctionné. Le dépassement est là. Le seul problème maintenant est que la carte suivante s'affiche, mais pas la carte précédente. Autrement dit, si je suis à la page 2, je peux voir la page 3, mais pas la page 1. Où aurais-je pu me tromper?
Swayam
2
@Swayam: Je n'ai aucune idée.
CommonsWare
110

J'ai une solution similaire:

Sur le viewpager, réglez le rembourrage gauche et droit, par exemple 20dp. Définissez également la marge de page sur le visionneur, par exemple la moitié du remplissage du pageur. Et n'oubliez pas de désactiver le remplissage du clip.

tilePager.setPadding(defaultGap, 0, defaultGap, 0);
tilePager.setClipToPadding(false);
tilePager.setPageMargin(halfGap);
Thomas R.
la source
2
Bonne solution fournie.
akash89
moyen le plus simple et le meilleur
HannahCarney
C'est la bête oui bête réponse pour envisager de nommer les valeurs xd
silentsudo
1
note latérale: cela ne fonctionnera pas avec un transformateur de téléavertisseur de vue personnalisé
voytez
@voytez une solution pour le transformateur?
Alex
76
  1. Définissez le remplissage gauche et droit pour la vue entière de l'élément Exemple xml (page_item.xml):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"/>
    
    <TextView
        android:id="@+id/text1"
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    
    </LinearLayout>
  2. Ensuite, définissez une marge de page négative PageViewégale à 2 * (remplissage de la vue précédente)

    int margin = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20*2,     getResources().getDisplayMetrics());
    mViewPager.setPageMargin(-margin);
  3. Optionnel. Définissez zéro remplissage à gauche pour le premier élément et zéro remplissage à droite pour le dernier élément pour masquer les bords vides. Vous pouvez le faire dans la classe PageAdapterou Pagefragment.

SergeyA
la source
@Sergey, je ne peux pas faire fonctionner cela avec votre solution, pourriez-vous poster un exemple? thx
Marckaraujo
12
il suffit d'ajouter une note: avec cette solution lorsque vous glissez de la page 1 à la page 2, la page 3 n'est pas en mémoire, elle apparaît donc avec un retard. pour résoudre ce problème, ajoutez simplement - yourViewPager.setOffscreenPageLimit (2);
José Barbosa
Je fais la même chose mais cela désactive l'effet de sur-défilement pour le dernier élément. Des pistes à ce sujet?
Swayam
Je n'arrive pas à faire fonctionner cela non plus ... les marges semblent s'afficher au hasard si j'utilise des images avec une échelle définie pour centrer le recadrage. Quelqu'un a-t-il un exemple de code fonctionnel à partager?
kenyee
2
Comment toucher le premier et le dernier élément? En vérifiant l'index des pages dans OnPageListener?
Hardik9850
47

Pour afficher l'aperçu des pages gauche et droite, définissez les deux valeurs suivantes

viewpager.setClipToPadding(false)
viewpager.setPadding(left,0,right,0)

Si vous avez besoin d'espace entre deux pages dans le viewpager, ajoutez viewpager.setPageMargin (int)

Android ViewPager - Afficher l'aperçu de la page à gauche et à droite

molu2008
la source
3
Cela devrait être la bonne réponse. Je pense que cela ne fonctionnait peut-être pas dans les versions précédentes de viewpager, mais cela fonctionne maintenant.
Greg Ennis
Il ajoute également la même marge sur le côté gauche de la première et à droite de la dernière page. Toute correction
Umesh Aawte
1
Réponse courte et plus claire.
Imran Ahmed
10

si quelqu'un cherche encore une solution, j'avais personnalisé la ViewPage pour y parvenir sans utiliser de marge négative, trouvez un exemple de projet ici https://github.com/44kksharma/Android-ViewPager-Carousel-UI cela devrait fonctionner dans la plupart des cas mais vous peut toujours définir la marge de page avec mPager.setPageMargin(margin in pixel);

44kksharma
la source
1

Téléchargez le code source à partir d'ici ( ViewPager avec les limites de page précédente et suivante )

MainActivity.java

package com.deepshikha.viewpager;

import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends FragmentActivity {

    ViewPager pager;
    MyPageAdapter obj_adapter;
    String str_device;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();


    }

    private void init() {
        pager = (ViewPager) findViewById(R.id.viewpager);
        differentDensityAndScreenSize(getApplicationContext());
        List<Fragment> fragments = getFragments();
        pager.setAdapter(obj_adapter);
        pager.setClipToPadding(false);


        if (str_device.equals("normal-hdpi")){
            pager.setPadding(160, 0, 160, 0);
        }else if (str_device.equals("normal-mdpi")){
            pager.setPadding(160, 0, 160, 0);
        }else if (str_device.equals("normal-xhdpi")){
            pager.setPadding(160, 0, 160, 0);
        }else if (str_device.equals("normal-xxhdpi")){
            pager.setPadding(180, 0, 180, 0);
        }else if (str_device.equals("normal-xxxhdpi")){
            pager.setPadding(180, 0, 180, 0);
        }else if (str_device.equals("normal-unknown")){
            pager.setPadding(160, 0, 160, 0);
        }else {

        }

        obj_adapter = new MyPageAdapter(getSupportFragmentManager(), fragments);
        pager.setPageTransformer(true, new ExpandingViewPagerTransformer());
        pager.setAdapter(obj_adapter);
    }

    class MyPageAdapter extends FragmentPagerAdapter {

        private List<Fragment> fragments;

        public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) {

            super(fm);

            this.fragments = fragments;

        }

        @Override

        public Fragment getItem(int position) {

            return this.fragments.get(position);

        }

        @Override

        public int getCount() {

            return this.fragments.size();

        }

    }

    private List<Fragment> getFragments() {

        List<Fragment> fList = new ArrayList<Fragment>();

        fList.add(MyFragment.newInstance("Fragment 1",R.drawable.imags));
        fList.add(MyFragment.newInstance("Fragment 2",R.drawable.image1));
        fList.add(MyFragment.newInstance("Fragment 3",R.drawable.image2));
        fList.add(MyFragment.newInstance("Fragment 4",R.drawable.image3));
        fList.add(MyFragment.newInstance("Fragment 5",R.drawable.image4));

        return fList;

    }

    public int differentDensityAndScreenSize(Context context) {
        int value = 20;
        String str = "";
        if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_SMALL) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    str = "small-ldpi";
                    // Log.e("small 1","small-ldpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    str = "small-mdpi";
                    // Log.e("small 1","small-mdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    str = "small-hdpi";
                    // Log.e("small 1","small-hdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    str = "small-xhdpi";
                    // Log.e("small 1","small-xhdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    str = "small-xxhdpi";
                    // Log.e("small 1","small-xxhdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    str = "small-xxxhdpi";
                    //Log.e("small 1","small-xxxhdpi");
                    value = 20;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    str = "small-tvdpi";
                    // Log.e("small 1","small-tvdpi");
                    value = 20;
                    break;
                default:
                    str = "small-unknown";
                    value = 20;
                    break;
            }

        } else if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    str = "normal-ldpi";
                    // Log.e("normal-ldpi 1","normal-ldpi");
                    str_device = "normal-ldpi";
                    value = 82;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    // Log.e("normal-mdpi 1","normal-mdpi");
                    str = "normal-mdpi";
                    value = 82;
                    str_device = "normal-mdpi";
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    // Log.e("normal-hdpi 1","normal-hdpi");
                    str = "normal-hdpi";
                    str_device = "normal-hdpi";
                    value = 82;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    //Log.e("normal-xhdpi 1","normal-xhdpi");
                    str = "normal-xhdpi";
                    str_device = "normal-xhdpi";
                    value = 90;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    // Log.e("normal-xxhdpi 1","normal-xxhdpi");
                    str = "normal-xxhdpi";
                    str_device = "normal-xxhdpi";
                    value = 96;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    //Log.e("normal-xxxhdpi","normal-xxxhdpi");
                    str = "normal-xxxhdpi";
                    str_device = "normal-xxxhdpi";
                    value = 96;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    //Log.e("DENSITY_TV 1","normal-mdpi");
                    str = "normal-tvdpi";
                    str_device = "normal-tvmdpi";
                    value = 96;
                    break;
                default:
                    // Log.e("normal-unknown","normal-unknown");
                    str = "normal-unknown";
                    str_device = "normal-unknown";
                    value = 82;
                    break;
            }
        } else if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    str = "large-ldpi";
                    // Log.e("large-ldpi 1","normal-ldpi");
                    value = 78;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    str = "large-mdpi";
                    //Log.e("large-ldpi 1","normal-mdpi");
                    value = 78;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    //Log.e("large-ldpi 1","normal-hdpi");
                    str = "large-hdpi";
                    value = 78;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    // Log.e("large-ldpi 1","normal-xhdpi");
                    str = "large-xhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    //Log.e("large-ldpi 1","normal-xxhdpi");
                    str = "large-xxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    // Log.e("large-ldpi 1","normal-xxxhdpi");
                    str = "large-xxxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    //Log.e("large-ldpi 1","normal-tvdpi");
                    str = "large-tvdpi";
                    value = 125;
                    break;
                default:
                    str = "large-unknown";
                    value = 78;
                    break;
            }

        } else if ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
            switch (context.getResources().getDisplayMetrics().densityDpi) {
                case DisplayMetrics.DENSITY_LOW:
                    // Log.e("large-ldpi 1","normal-ldpi");
                    str = "xlarge-ldpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_MEDIUM:
                    // Log.e("large-ldpi 1","normal-mdpi");
                    str = "xlarge-mdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_HIGH:
                    //Log.e("large-ldpi 1","normal-hdpi");
                    str = "xlarge-hdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XHIGH:
                    // Log.e("large-ldpi 1","normal-hdpi");
                    str = "xlarge-xhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXHIGH:
                    // Log.e("large-ldpi 1","normal-xxhdpi");
                    str = "xlarge-xxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_XXXHIGH:
                    // Log.e("large-ldpi 1","normal-xxxhdpi");
                    str = "xlarge-xxxhdpi";
                    value = 125;
                    break;
                case DisplayMetrics.DENSITY_TV:
                    //Log.e("large-ldpi 1","normal-tvdpi");
                    str = "xlarge-tvdpi";
                    value = 125;
                    break;
                default:
                    str = "xlarge-unknown";
                    value = 125;
                    break;
            }
        }

        return value;
    }
}
Deepshikha Puri
la source
1
Ce code ne fonctionne pas correctement, il affiche la page du côté gauche un peu plus grande que le côté droit
Chirag Joshi
1

Il y a quelque temps je avais besoin cette fonctionnalité et préparé une petite bibliothèque qui utilise RecyclerViewavec PagerSnapHelper (ajoutée dans la version 25.1.0 de la bibliothèque de soutien v7) au lieu de classique ViewPager:

MetalRecyclerPagerView - vous pouvez trouver tout le code avec des exemples ici.

Il se compose principalement d'un fichier de classe unique: MetalRecyclerViewPager.java (et de deux xml: attrs.xml et ids.xml ).

J'espère que cela aide quelqu'un :)

Alexandre Bilchuk
la source