Android: Vertical ViewPager [fermé]

131

Existe-t-il un moyen de faire un ViewPagerqui ne défile pas horizontalement, mais verticalement?!

user1709805
la source
1
Il existe une nouvelle implémentation open source non officielle d'un ViewPager vertical: Annonce: plus.google.com/107777704046743444096/posts/1FTJfrvnY8w Code: github.com/LambergaR/VerticalViewPager
Vasily Sochinsky
Il existe une nouvelle implémentation basée sur la bibliothèque de support 19: github.com/castorflex/VerticalViewPager
Vasily Sochinsky
Ce n'est pas la même chose que github.com/castorflex/VerticalViewPager , bien qu'il ait un nom similaire.
Flimm
1
Il y a un contrôle appelé ViewPager2, vérifiez ici pour la démo stackoverflow.com/a/54643817/7666442
Nilesh Rathod

Réponses:

227

Vous pouvez utiliser un ViewPager.PageTransformer pour donner l'illusion d'une verticale ViewPager. Pour obtenir un défilement avec un glissement vertical au lieu d'un glissement horizontal, vous devrez remplacer ViewPagerles événements tactiles par défaut et permuter les coordonnées de MotionEvents avant de les gérer, par exemple:

/**
 * Uses a combination of a PageTransformer and swapping X & Y coordinates
 * of touch events to create the illusion of a vertically scrolling ViewPager. 
 * 
 * Requires API 11+
 * 
 */
public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        super(context);
        init();
    }

    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        // The majority of the magic happens here
        setPageTransformer(true, new VerticalPageTransformer());
        // The easiest way to get rid of the overscroll drawing that happens on the left and right
        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements ViewPager.PageTransformer {

        @Override
        public void transformPage(View view, float position) {

            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);

            } else if (position <= 1) { // [-1,1]
                view.setAlpha(1);

                // Counteract the default slide transition
                view.setTranslationX(view.getWidth() * -position);

                //set Y position to swipe in from top
                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);

            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

    /**
     * Swaps the X and Y coordinates of your touch event.
     */
    private MotionEvent swapXY(MotionEvent ev) {
        float width = getWidth();
        float height = getHeight();

        float newX = (ev.getY() / height) * width;
        float newY = (ev.getX() / width) * height;

        ev.setLocation(newX, newY);

        return ev;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev){
        boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
        swapXY(ev); // return touch coordinates to original reference frame for any child views
        return intercepted;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(swapXY(ev));
    }

}

Bien sûr, vous pouvez modifier ces paramètres comme bon vous semble. Finit par ressembler à ceci:

Démo de VerticalViewPager

Brett
la source
4
@Der Golem comment utiliser la mise en page pour cela?
bShah le
Quelle est la question exacte? Au fait, je n'ai pas posté la réponse, j'ai simplement ajouté l'image référencée.
Phantômaxx
1
@Brett dans cet exemple, je souhaite effectuer une action en glissant vers la gauche et la droite. comment faire
Prabs
1
@Brett ça marche comme prévu, la transition se fait verticalement. Mais le problème est que je dois balayer vers la droite / gauche pour faire la transition et en glissant haut / bas aucune transition n'a lieu.
Karan Khurana
2
@Brett J'utilisais votre solution. mais maintenant, je reçois le problème de swipping dans les appareils Andorid Pie. Quelqu'un est-il confronté au même problème?
Jishant
21

J'ai une solution qui fonctionne pour moi en deux étapes.

  1. onInstantiateItem()de PagerAdapter, créez la vue et faites-la pivoter de -90:

    view.setRotation(-90f)

    Si vous utilisez FragmentPagerAdapter, alors:

    objFragment.getView().setRotation(-90)
  2. Faire pivoter la ViewPagervue de 90 degrés:

    objViewPager.setRotation(90)

Fonctionne comme un charme au moins pour mon exigence.

Kulai
la source
4
cette solution fonctionne, MAIS vous devez toujours glisser horizontalement alors que le viewPager défile maintenant verticalement
leochab
@Kulai je ne sais pas quoi faire ici. Pouvez-vous s'il vous plaît expliquer un peu selon ma compréhension que nous avons public Object instantiateItem (conteneur ViewGroup, position int) ici, nous devons faire container.setRotation (-90f);
varun
1
Cela fonctionne comme un charme! Bien que la vue soit coupée dans la partie supérieure et inférieure, et je ne comprends pas pourquoi: - /
Nivaldo Bondança
2
Cela fonctionne correctement pour une image carrée et non pour un rectangulaire. Les dimensions vont mal lors de la rotation d'un rectangle.
Kulai
1
Je ne sais pas qui a voté cette réponse. ce n'est pas VerticalViewPager, c'est ViewPager avec une rotation de 90 degrés, le geste et la transition sont juste en face. et ce n'est pas du tout naturel
droidev
20

Vue verticalePager

Les autres réponses ici semblaient toutes avoir des problèmes avec elles. Même les projets open source recommandés ne fusionnaient pas les demandes d'extraction récentes avec des corrections de bogues. Ensuite, j'ai trouvé VerticalViewPagerde Google qu'ils utilisaient une application DeskClock. Je fais beaucoup plus confiance à l'utilisation de la mise en œuvre de Google qu'aux autres réponses qui flottent ici. (La version de Google est similaire à la réponse actuelle la plus votée, mais plus complète.)

Exemple complet

Cet exemple est presque exactement le même que mon exemple de base ViewPager , avec quelques modifications mineures pour utiliser la VerticalViewPagerclasse.

entrez la description de l'image ici

XML

Ajoutez les mises en page xml pour l'activité principale et pour chaque page (fragment). Notez que nous utilisons VerticalViewPagerplutôt que la norme ViewPager. Je vais inclure le code ci-dessous.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.verticalviewpager.MainActivity">

    <com.example.myapp.VerticalViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

fragment_one.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textview"
        android:textSize="30sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

Code

Le code pour le VerticalViewPagern'est pas le mien. Il s'agit simplement d'une version allégée (sans commentaires) du code source de Google. Découvrez celui-ci pour la version la plus à jour. Les commentaires sont également utiles pour comprendre ce qui se passe.

VerticalViewPager.java

import android.support.v4.view.ViewPager;    

public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        this(context, null);
    }

    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    @Override
    public boolean canScrollHorizontally(int direction) {
        return false;
    }

    @Override
    public boolean canScrollVertically(int direction) {
        return super.canScrollHorizontally(direction);
    }

    private void init() {
        setPageTransformer(true, new VerticalPageTransformer());
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final boolean toIntercept = super.onInterceptTouchEvent(flipXY(ev));
        flipXY(ev);
        return toIntercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final boolean toHandle = super.onTouchEvent(flipXY(ev));
        flipXY(ev);
        return toHandle;
    }

    private MotionEvent flipXY(MotionEvent ev) {
        final float width = getWidth();
        final float height = getHeight();
        final float x = (ev.getY() / height) * width;
        final float y = (ev.getX() / width) * height;
        ev.setLocation(x, y);
        return ev;
    }

    private static final class VerticalPageTransformer implements ViewPager.PageTransformer {
        @Override
        public void transformPage(View view, float position) {
            final int pageWidth = view.getWidth();
            final int pageHeight = view.getHeight();
            if (position < -1) {
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);
                view.setTranslationX(pageWidth * -position);
                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);
            } else {
                view.setAlpha(0);
            }
        }
    }
}

MainActivity.java

J'ai seulement échangé VerticalViewPagerpour ViewPager.

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

public class MainActivity extends AppCompatActivity {

    static final int NUMBER_OF_PAGES = 2;

    MyAdapter mAdapter;
    VerticalViewPager mPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAdapter = new MyAdapter(getSupportFragmentManager());
        mPager = findViewById(R.id.viewpager);
        mPager.setAdapter(mAdapter);
    }

    public static class MyAdapter extends FragmentPagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUMBER_OF_PAGES;
        }

        @Override
        public Fragment getItem(int position) {

            switch (position) {
                case 0:
                    return FragmentOne.newInstance(0, Color.WHITE);
                case 1:
                    // return a different Fragment class here
                    // if you want want a completely different layout
                    return FragmentOne.newInstance(1, Color.CYAN);
                default:
                    return null;
            }
        }
    }

    public static class FragmentOne extends Fragment {

        private static final String MY_NUM_KEY = "num";
        private static final String MY_COLOR_KEY = "color";

        private int mNum;
        private int mColor;

        // You can modify the parameters to pass in whatever you want
        static FragmentOne newInstance(int num, int color) {
            FragmentOne f = new FragmentOne();
            Bundle args = new Bundle();
            args.putInt(MY_NUM_KEY, num);
            args.putInt(MY_COLOR_KEY, color);
            f.setArguments(args);
            return f;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mNum = getArguments() != null ? getArguments().getInt(MY_NUM_KEY) : 0;
            mColor = getArguments() != null ? getArguments().getInt(MY_COLOR_KEY) : Color.BLACK;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.fragment_one, container, false);
            v.setBackgroundColor(mColor);
            TextView textView = v.findViewById(R.id.textview);
            textView.setText("Page " + mNum);
            return v;
        }
    }
}

Fini

Vous devriez pouvoir exécuter l'application et voir le résultat dans l'animation ci-dessus.

Voir également

Suragch
la source
3
Le code fonctionne bien, il suffit d'une petite aide.Dans le code actuel, nous devons glisser de bas en haut pour obtenir la page suivante, mais je veux que même un petit balayage devrait également obtenir la page suivante.
AMIT
14

Pour quelqu'un qui a du mal à faire fonctionner ViewPager vertical à l'horizontale, faites simplement les choses suivantes:

Vue verticalePager

public class VerticalViewPager extends ViewPager {
    public VerticalViewPager(Context context) {
        super(context);
        init();
    }

    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setPageTransformer(true, new VerticalPageTransformer());
        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements ViewPager.PageTransformer {

        @Override
        public void transformPage(View view, float position) {

            if (position < -1) {
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);

                view.setTranslationX(view.getWidth() * -position);

                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);
            } else {
                view.setAlpha(0);
            }
        }
    }

    private MotionEvent swapXY(MotionEvent ev) {
        float width = getWidth();
        float height = getHeight();

        float newX = (ev.getY() / height) * width;
        float newY = (ev.getX() / width) * height;

        ev.setLocation(newX, newY);

        return ev;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
        swapXY(ev);
        return intercepted;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(swapXY(ev));
    }

}

Vue horizontalePager

public class HorizontalViewPager extends ViewPager {
    private GestureDetector xScrollDetector;

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

    public HorizontalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        xScrollDetector = new GestureDetector(getContext(), new XScrollDetector());
    }

    class XScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return Math.abs(distanceX) > Math.abs(distanceY);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (xScrollDetector.onTouchEvent(ev)) {
            super.onInterceptTouchEvent(ev);
            return true;
        }

        return super.onInterceptTouchEvent(ev);
    }

}
Plongeurs
la source
Comment puis-je ajouter ce pager de vue horizontale et verticale à ma vue?
user1810931
Commencez avec le tutoriel - vogella.com/tutorials/AndroidCustomViews/article.html
Divers
Comment implémenter les classes de pagineur de vue horizontale et verticale ci-dessus dans ma vue? L'extrait de code aide
user1810931
ViewPager est déjà affiché, je ne comprends pas ce que vous demandez.
Divers
J'utilise une bibliothèque appelée "Material Calendar View" ( github.com/prolificinteractive/material-calendarview ) et elle contient déjà un viewpager horizontal et je voulais y ajouter un viewpager vertical.
user1810931
8

Une légère extension cette réponse m'a aidé à réaliser mon exigence (Vertical View Pager pour animer similaire comme dans Inshorts - News en 60 mots )

public class VerticalViewPager extends ViewPager {

public VerticalViewPager(Context context) {
    super(context);
    init();
}

public VerticalViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

private void init() {
    // The majority of the magic happens here
    setPageTransformer(true, new VerticalPageTransformer());
    // The easiest way to get rid of the overscroll drawing that happens on the left and right
    setOverScrollMode(OVER_SCROLL_NEVER);
}

private class VerticalPageTransformer implements ViewPager.PageTransformer {
 private static final float MIN_SCALE = 0.75f;
    @Override
    public void transformPage(View view, float position) {

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        }  else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page
            view.setAlpha(1);
            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);

            //set Y position to swipe in from top
            float yPosition = position * view.getHeight();
            view.setTranslationY(yPosition);
            view.setScaleX(1);
            view.setScaleY(1);

        } else if (position <= 1) { // [0,1]
            view.setAlpha(1);

            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);


            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }

    }

}

/**
 * Swaps the X and Y coordinates of your touch event.
 */
private MotionEvent swapXY(MotionEvent ev) {
    float width = getWidth();
    float height = getHeight();

    float newX = (ev.getY() / height) * width;
    float newY = (ev.getX() / width) * height;

    ev.setLocation(newX, newY);

    return ev;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
    boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
    swapXY(ev); // return touch coordinates to original reference frame for any child views
    return intercepted;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}
}

J'espère que cela pourra être utile à quelqu'un d'autre.

Amrut Bidri
la source
1
Valeur idéale pour MIN_SCALE?
divyenduz
Vous n'avez pas trouvé de problème de balayage rapide, la transition n'est pas fluide
Praneeth
Pourquoi diable quelqu'un balayerait-il rapidement?
Amrut Bidri
Juste un commentaire pour clarifier: Cette solution modifie l'animation de manière à ce que la nouvelle page ne vienne pas d'en bas mais plutôt de derrière l'ancienne page. Donc, fondamentalement, vous n'avez pas de pages placées les unes à côté des autres, mais plutôt un jeu de pages superposées. Donc, cette solution n'est peut-être pas ce que la question initiale essaie de faire.
Benjamin Basmaci
4

Il y a quelques projets open source qui prétendent faire cela. Les voici:

Ceux-ci ont été marqués comme obsolètes par leurs auteurs:

Et encore une chose:

Flimm
la source
3

Vérifiez ceci: https://github.com/JakeWharton/Android-DirectionalViewPager

Ou la question suivante peut vous aider: Vertical "Gridview avec pages" ou "Viewpager"

sdabet
la source
2
Il faut garder à l'esprit que le DirectionalViewPagern'a pas été mis à jour depuis un certain temps et qu'il manque donc certaines des nouvelles fonctionnalités de la ViewPagerdans la bibliothèque de support; ie setPageMargin(int). En général, il devrait faire le travail. Et sinon, il n'est pas trop difficile de récupérer le code source ViewPageret de remplacer toutes les logiques x / y et largeur / hauteur.
MH.
J'ai déjà pris en compte le DirectionalViewPagermais, comme MH l'a dit, il n'est pas mis à jour (son développeur le considère comme DÉPRECÉ) !! C'est incroyable que les développeurs Android ViewPagern'aient pas fourni à la communauté un vertical , mais seulement un horizon. Je suis plus récent sur Android, développer mon ViewPageréchange vertical x / y n'est pas si facile pour moi .. je préférerais une solution déjà construite .. de toute façon, merci
user1709805
2
salut, avez-vous réussi à faire le viewpager vertical ?? thansk
Paul
3

Juste une amélioration sur les réponses de @Brett et @ Salman666 pour transformer correctement les coordonnées (X, Y) en (Y, X) puisque les affichages de l'appareil sont rectangulaires:

...

/**
 * Swaps the X and Y coordinates of your touch event
 */
@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return super.onInterceptTouchEvent(swapXY(ev));
}

private MotionEvent swapXY(MotionEvent ev) {

    //Get display dimensions
    float displayWidth=this.getWidth();
    float displayHeight=this.getHeight();

    //Get current touch position
    float posX=ev.getX();
    float posY=ev.getY();

    //Transform (X,Y) into (Y,X) taking display dimensions into account
    float newPosX=(posY/displayHeight)*displayWidth;
    float newPosY=(1-posX/displayWidth)*displayHeight;

    //swap the x and y coords of the touch event
    ev.setLocation(newPosX, newPosY);

    return ev;
}

...

Cependant, quelque chose doit encore être fait pour améliorer la réactivité de l'écran tactile. Le problème pourrait être lié à ce que @msdark a commenté sur la réponse de @ Salman666.

Anonyme
la source
J'ai quelques améliorations en retournant toujours truedans onInterceptTouchEventet je l' ai aussi modifié les raccourcis clavier, de sorte que l' aide d' un DEPA il déclenche les boutons HAUT / BAS au lieu de gauche / droite: gist.github.com/zevektor/fbacf4f4f6c39fd6e409
Vektor88
@ Vektor88 retournant toujours vrai empêchera les vues intérieures de recevoir des événements tactiles .. la meilleure solution est comme dans la réponse brett ..
Mohammad Zekrallah
2
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        super(context);
        init();
    }


    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {

        setPageTransformer(true, new VerticalPageTransformer());

        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements PageTransformer {

        @Override
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            int pageHeight = view.getHeight();

            if (position < -1) {

                view.setAlpha(0);

            } else if (position <= 1) {
                view.setAlpha(1);


                view.setTranslationX(pageWidth * -position);


                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);

            } else {

                view.setAlpha(0);
            }
        }
    }
        @Override
    public boolean onTouchEvent(MotionEvent ev) {

        ev.setLocation(ev.getY(), ev.getX());

        return super.onTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        ev.setLocation(ev.getY(), ev.getX());
        return super.onInterceptTouchEvent(ev);
    }
}
Salman666
la source
1
Cela fonctionne très bien, mais je perds le touchEvent sur les éléments ou les événements gauche /
swipe
0

Il y en a déjà un dans la source Android . Je l'ai cependant modifié pour qu'il fonctionne mieux:

package com.crnlgcs.sdk.widgets;



import android.content.Context;
import android.support.v4.view.ViewConfigurationCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;

public class VerticalViewPager extends ViewPager {
    private static final String TAG = "VerticalViewPager";
    private static final boolean DEBUG = true;

    private float mLastMotionX;
    private float mLastMotionY;
    private float mTouchSlop;
    private boolean mVerticalDrag;
    private boolean mHorizontalDrag;

    // Vertical transit page transformer
    private final ViewPager.PageTransformer mPageTransformer = new ViewPager.PageTransformer() {
        @Override
        public void transformPage(View view, float position) {
            final int pageWidth = view.getWidth();
            final int pageHeight = view.getHeight();
            if (position < -1) {
                // This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);
                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);
                // set Y position to swipe in from top
                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);
            } else {
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    };

    public VerticalViewPager(Context context) {
        super(context, null);
    }

    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
        init();
    }

    private void init() {
        // Make page transit vertical
        setPageTransformer(true, mPageTransformer);
        // Get rid of the overscroll drawing that happens on the left and right (the ripple)
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        final float x = ev.getX();
        final float y = ev.getY();

        if (DEBUG) Log.v(TAG, "onTouchEvent " + x + ", " + y);

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mLastMotionX = x;
                mLastMotionY = y;
                if (!super.onTouchEvent(ev))
                    return false;
                return verticalDrag(ev);
            }
            case MotionEvent.ACTION_MOVE: {
                final float xDiff = Math.abs(x - mLastMotionX);
                final float yDiff = Math.abs(y - mLastMotionY);
                if (!mHorizontalDrag && !mVerticalDrag) {
                    if (xDiff > mTouchSlop && xDiff > yDiff) { // Swiping left and right
                        mHorizontalDrag = true;
                    } else if (yDiff > mTouchSlop && yDiff > xDiff) { //Swiping up and down
                        mVerticalDrag = true;
                    }
                }
                if (mHorizontalDrag) {
                    return super.onTouchEvent(ev);
                } else if (mVerticalDrag) {
                    return verticalDrag(ev);
                }
            }
            case MotionEvent.ACTION_UP: {
                if (mHorizontalDrag) {
                    mHorizontalDrag = false;
                    return super.onTouchEvent(ev);
                }
                if (mVerticalDrag) {
                    mVerticalDrag = false;
                    return verticalDrag(ev);
                }
            }
        }
        // Set both flags to false in case user lifted finger in the parent view pager
        mHorizontalDrag = false;
        mVerticalDrag = false;

        return false;
    }


    private boolean verticalDrag(MotionEvent ev) {
        final float x = ev.getX();
        final float y = ev.getY();
        ev.setLocation(y, x);
        return super.onTouchEvent(ev);
    }
}
phreakhead
la source
cela ne fonctionne pas correctement .. même la version source Android ne le fait pas .. c'est glitchy et ne fonctionne que pour les gestes droite / gauche .. si vous faites haut / bas ça ne défile pas .. du moins pour moi ..
Mohammad Zekrallah
0

Un référentiel actuellement plus actif est lsjwzh / RecyclerViewPager .

  • dernier commit 12 août 2016, 16 Contributeurs, 1840 étoiles
  • basé sur RecyclerView
ford04
la source
0

Il s'agit d'une implémentation de ViewPager à défilement vertical. Fonctionne bien avec RecyclerView et ListView. guochong / VerticalViewPager .

utilisez ViewPager.PageTransformer pour faire défiler ViewPager verticalement et fournissez également un View.OnTouchListener pour gérer le conflit de défilement.

/**
 * 1.dispatch ACTION_DOWN,ACTION_UP,ACTION_CANCEL to child<br>
 * 2.hack ACTION_MOVE
 *
 * @param v
 * @param e
 * @return
 */
@Override
public boolean onTouch(View v, MotionEvent e) {
    Log.i(TAG, "onTouchEvent " + ", action " + e.getAction() + ", e.rawY " + e.getRawY() + ",lastMotionY " + lastMotionY + ",downY " + downY);
    switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downY = e.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:

            if (downY == Float.MIN_VALUE && lastMotionY == Float.MIN_VALUE) {
                //not start from MOTION_DOWN, the child dispatch this first motion
                downY = e.getRawY();
                break;
            }

            float diff = e.getRawY() - (lastMotionY == Float.MIN_VALUE ? downY : lastMotionY);
            lastMotionY = e.getRawY();
            diff = diff / 2; //slow down viewpager scroll
            Log.e(TAG, "scrollX " + dummyViewPager.getScrollX() + ",basescrollX " + dummyViewPager.getBaseScrollX());

            if (dummyViewPager.getScrollX() != dummyViewPager.getBaseScrollX()) {
                if (fakeDragVp(v, e, diff)) return true;
            } else {
                if (ViewCompat.canScrollVertically(v, (-diff) > 0 ? 1 : -1)) {
                    Log.e(TAG, "scroll vertically  " + diff + ", move.lastMotionY " + e.getY());
                    break;
                } else {
                    dummyViewPager.beginFakeDrag();
                    fakeDragVp(v, e, diff);
                    adjustDownMotion(v, e);
                    return true;
                }
            }

            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            if (dummyViewPager.isFakeDragging()) {
                try {
                    dummyViewPager.endFakeDrag();
                } catch (Exception e1) {
                    Log.e(TAG, "", e1);
                }
            }
            reset();
            break;
    }

    return false;
}
tchad
la source
Bienvenue dans StackOverflow et merci pour votre aide. Vous voudrez peut-être améliorer encore votre réponse en ajoutant du code.
Elias MP
0

Même moi, je faisais face au même problème en rendant ViewPager vertical en échangeant X et Y. Ce n'était pas du tout fluide.

C'est parce qu'il ne fonctionnait que lorsque l'angle de balayage était inférieur à 7,125 degrés = arctan (1/8) pendant l'interception et 14 degrés = arctan (1/4) pendant le toucher; comme original ViewPager horizontal un travail lorsque l'angle de balayage est inférieur à 26,565 degrés = arctan (1/2) pendant l'interception et 45 degrés = arctan (1) pendant le toucher.

C'est pourquoi j'ai copié le code d'Android support-core-ui et déplacé les valeurs vers des variables, que j'ai multipliées par réflexion.

Veuillez trouver le code et le README sur https://github.com/deepakmishra/verticalviewpager et VerticalViewPager sur https://github.com/deepakmishra/verticalviewpager/blob/master/app/src/main/java/com/viewpager/VerticalViewPager .Java

Deepak
la source
0

la meilleure façon est de faire pivoter le visualiseur de 90 degrés et d'utiliser constraintLayout pour ajuster l'emplacement.

JackHui
la source
0

J'ai fini par créer un nouveau DirectionalViewPager qui peut faire défiler verticalement ou horizontalement car toutes les solutions que j'ai vues ici ont des défauts:

  1. Implémentations existantes de VerticalViewPager (par castorflex et LambergaR)

    • Ils sont basés sur de très anciennes versions de bibliothèques de support.
  2. Astuce de transformation avec échange de coordonnées

    • Le surcroller est toujours affiché à partir des bords gauche / droit.
    • Le basculement de page ne fonctionne pas correctement, car même avec les coordonnées permutées, VelocityTracker.computeCurrentVelocitycalcule toujours la vitesse avec l'axe X, probablement parce que cela utilise en interne un appel natif qui ignore l'échange de coordonnées.
  3. Afficher la rotation

    • Hack qui nécessite que chaque vue enfant soit également tournée.
    • Si vous voulez lire les coordonnées pour autre chose, vous devez permuter l'axe.
Inorichi
la source