Comment désactiver la pagination en glissant avec le doigt dans ViewPager tout en étant capable de balayer par programme?

550

J'ai ViewPager et en dessous, j'ai 10 boutons. En cliquant sur le bouton, par exemple # 4, le pager passe immédiatement à la page # 4 de mPager.setCurrentItem(3);. Mais, je veux désactiver la pagination en glissant avec le doigt horizontalement. Ainsi, la pagination se fait UNIQUEMENT en cliquant sur les boutons. Alors, comment puis-je désactiver le balayage avec le doigt?

théatre
la source
Que diriez-vous d'utiliser ViewFlipper en premier lieu? Cela vous évitera beaucoup de maux de tête.
Alex Semeniuk

Réponses:

885

Vous devez sous-classer ViewPager. onTouchEventcontient beaucoup de bonnes choses que vous ne voulez pas changer, comme autoriser les vues enfants à toucher. onInterceptTouchEventc'est ce que vous voulez changer. Si vous regardez le code pour ViewPager, vous verrez le commentaire:

    /*
     * This method JUST determines whether we want to intercept the motion.
     * If we return true, onMotionEvent will be called and we do the actual
     * scrolling there.
     */

Voici une solution complète:

Tout d'abord, ajoutez cette classe à votre srcdossier:

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
import java.lang.reflect.Field;

public class NonSwipeableViewPager extends ViewPager {

    public NonSwipeableViewPager(Context context) {
        super(context);
        setMyScroller();
    }

    public NonSwipeableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setMyScroller();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    //down one is added for smooth scrolling

    private void setMyScroller() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new MyScroller(getContext()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class MyScroller extends Scroller {
        public MyScroller(Context context) {
            super(context, new DecelerateInterpolator());
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
        }
    }
}

Ensuite, assurez-vous d'utiliser cette classe au lieu de la régulière ViewPager, que vous avez probablement spécifiée comme android.support.v4.view.ViewPager. Dans votre fichier de mise en page, vous voudrez le spécifier avec quelque chose comme:

<com.yourcompany.NonSwipeableViewPager
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />

Cet exemple particulier est dans un LinearLayoutet est destiné à occuper tout l'écran, c'est pourquoi layout_weightest 1 etlayout_height est 0dp.

Et la setMyScroller();méthode est pour une transition en douceur

louielouie
la source
3
@louielouie En passant: y a-t-il une raison particulière pour laquelle vous avez choisi la solution 0dptaille / 1poids plutôt que la match_parenthauteur pour obtenir l'effet plein écran? Améliorez-vous les performances en procédant ainsi?
ubuntudroid
29
Cette réponse n'empêche pas le balayage de page lors de l'utilisation des touches gauche / droite du clavier (essayez-le dans l'émulateur). Ce n'est peut-être pas un problème pour les appareils tactiles, mais avec la télévision et les ordinateurs portables, il peut en être un.
Vincent Mimoun-Prat
8
@MarvinLabs @Thorbear La bonne façon de désactiver le défilement de la page par le clavier est de remplacer le executeKeyEvent(). C'est la méthode qui appelle ensuite allowScroll(). // Never allow swiping by keyboard LEFT, RIGHT, TAB and SHIFT+TAB keys @Override public boolean executeKeyEvent(KeyEvent event) { return false; }
araks
6
eh bien, cela désactive également le défilement vertical ... c'est mauvais, si vous utilisez des vues de liste.
maysi
5
J'espère que Google aurait pu fournir une méthode à laquelle nous fournissons notre méthode d'interface sur la façon de gérer les touchers / glissements, car je pense que cela ne ferait pas de mal?
Neon Warge
466

L'extension plus générale de ViewPagerserait de créer une SetPagingEnabledméthode afin que nous puissions activer et désactiver la pagination à la volée. Pour activer / désactiver le balayage, remplacez simplement deux méthodes: onTouchEventet onInterceptTouchEvent. Les deux renverront "false" si la pagination a été désactivée.

public class CustomViewPager extends ViewPager {

    private boolean enabled;

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onInterceptTouchEvent(event);
        }

        return false;
    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    } 
}

Sélectionnez ensuite ceci au lieu du viewpager intégré en XML

<mypackage.CustomViewPager 
    android:id="@+id/myViewPager" 
    android:layout_height="match_parent" 
    android:layout_width="match_parent" />

Il vous suffit d'appeler la setPagingEnabledméthode avec falseet les utilisateurs ne pourront pas glisser pour paginer.

Rajul
la source
3
Fonctionne parfaitement pour une vue qui a plusieurs sous-vues où l'on utilise le défilement horizontal (par exemple, le graphique AChartEngine). Dans mon fragment, j'utilise un rappel de mon activité lui disant d'activer ou de désactiver la pagination selon que l'utilisateur a touché (ACTION_MOVE) le graphique ou l'a quitté (ACTION_CANCEL). Merci beaucoup!
riper
32
Vous pouvez simplifier vos méthodes onTouchEventet onInterceptTouchEventavecreturn enabled && super.onTouchEvent(event);
nbarraille
2
@nbarraille c'est juste une question de style. Vous pouvez utiliser n'importe quel style qui vous semble plus lisible.
Rajul
7
Je recommanderais également de changer le nom du champ de "activé" en "swipePageChangeEnabled" ou quelque chose comme ça. Un mois après avoir écrit le code, vous vous souviendrez à peine de ce que signifie "activé", en particulier lorsque votre classe est appelée "CustomViewPager", où il n'est pas clair ce qu'est la personnalisation. C'est aussi une question de style, mais le style est important si vous ne voulez pas vous retrouver avec un projet non compatible, il est plus facile de réécrire complètement que de le réparer.
bytefu
4
Où dois-je appeler setPagingEnabled? ._.
Ntikki
107

La façon la plus simple est de setOnTouchListeneret retour truepour ViewPager.

mPager.setOnTouchListener(new OnTouchListener()
    {           
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            return true;
        }
    });
Wayne
la source
53
Ne fonctionne pas parfois. J'utilise un ViewPager avec un FragmentPagerAdapter et plusieurs Fragment. Après avoir défini OnTouchListener sur pager, si je lance à gauche, l'interface utilisateur se déplacera toujours un peu à gauche.
Chris.Zou
16
Cela fonctionne lorsque vous ajoutez pager.setCurrentItem(pager.getCurrentItem());avant de revenir true.
dng
1
cela a fonctionné pour moi avant. aucune idée pourquoi cela ne fonctionne plus bien.
développeur Android
semble fonctionner pour moi. Pour résoudre certains problèmes de mise en page que j'ai public int getItemPosition(Object object) { return POSITION_NONE; }dans mon adaptateur, ce qui force la recréation des pages et peut-être aussi la résolution d'autres problèmes.
r-hold
6
Il s'agit d'une solution PARTIELLEMENT fonctionnelle. Les balayages horizontaux sont traités d'une manière étrange. J'ai testé cela avec un Drag'n Drop Gridview dans le cadre d'un ViewPager. Lorsque vous faites glisser en utilisant cette solution, le glisser de gauche à droite et de droite à gauche échoue. Personnellement, je trouve l'approche de Rajul la meilleure.
Ton Snoei
58

Mieux vaut le déclarer styleable, donc vous pouvez changer sa propriété de xml:

private boolean swipeable;

public MyViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyViewPager);
    try {
        swipeable = a.getBoolean(R.styleable.MyViewPager_swipeable, true);
    } finally {
        a.recycle();
    }
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return swipeable ? super.onInterceptTouchEvent(event) : false;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return swipeable ? super.onTouchEvent(event) : false;
}

Et dans vos valeurs / attr.xml:

<declare-styleable name="MyViewPager">
  <attr name="swipeable" format="boolean" />
</declare-styleable>

afin que vous puissiez l'utiliser dans votre mise en page xml:

<mypackage.MyViewPager
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/viewPager"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:swipeable="false" />

Bien sûr, vous pouvez toujours avoir une propriété get / set.

Pietro
la source
58

Remplacement uniquement onTouchEventetonInterceptTouchEvent ne suffit pas si vous avez ViewPager lui-même dans un autre ViewPager. Le ViewPager enfant volerait les événements tactiles de défilement horizontal du ViewPager parent à moins qu'il ne soit positionné sur sa première / dernière page.

Pour que cette configuration fonctionne correctement, vous devez également remplacer la canScrollHorizontallyméthode.

Voir LockableViewPagerimplémentation ci-dessous.

public class LockableViewPager extends ViewPager {

    private boolean swipeLocked;

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

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

    public boolean getSwipeLocked() {
        return swipeLocked;
    }

    public void setSwipeLocked(boolean swipeLocked) {
        this.swipeLocked = swipeLocked;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return !swipeLocked && super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return !swipeLocked && super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean canScrollHorizontally(int direction) {
        return !swipeLocked && super.canScrollHorizontally(direction);
    }

}
sidon
la source
3
Merci, cela fonctionne très bien sur un ViewPager à l'intérieur d'un autre ViewPager.
Fernanda Bari
1
Cela fonctionne pour moi, également pour un ViewPager dans un autre ViewPager. La bonne solution n'a pas fonctionné pour moi dans ce cas.
Rafael Ruiz Muñoz
arrête également l'animation lorsqu'elle est utilisée dans des onglets.
Rishabh Srivastava
Si je le désactive et suppose que je veux l'activer, où puis-je obtenir l'événement pour appeler setSwipeLocked (false)?
Ravi Yadav
58

Maintenant, nous n'avons plus besoin de créer de coutume ViewPager

Un nouveau ViewPager2 nom Voir disponible dans Android

Support d'orientation verticale

  • ViewPager2prend en charge la pagination verticale en plus de la pagination horizontale traditionnelle. Vous pouvez activer la pagination verticale pour un ViewPager2élément en définissant son android:orientationattribut

Utilisation de XML

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:orientation="vertical" />

Utiliser du code

Pour désactiver le balayage en cours d' viewpager2utilisation

viewPager2.setUserInputEnabled(false);

Pour activer le balayage en cours d' viewpager2utilisation

viewPager2.setUserInputEnabled(true);

pour plus d'informations, vérifiez ceci

MISE À JOUR

Nilesh Rathod
la source
3
C'est génial, mais semble encore incomplet. Je l'ai essayé avec 5 fragments différents et après avoir basculé entre les pages, l'un des fragments était en quelque sorte perdu, c'est-à-dire que la vue n'était ni restaurée ni regonflée
Toochka
@Toochka désolé d'apprendre que pour moi ça marche bien, vous pouvez trouver l'exemple de code de travail ici stackoverflow.com/a/54643817/7666442 si possible, partagez votre code
Nilesh Rathod
1
J'ai réussi à désactiver le balayage sur un ViewPager2 à l'aide de cette méthode
voghDev
1
@voghDev heureux d'entendre cela
Nilesh Rathod
1
@PhaniRithvij veuillez vérifier cette réponse stackoverflow.com/a/54643817/7666442 J'ai ajouté tous les détails sur l'utilisation viewpager2avecRecyclerView.Adapter
Nilesh Rathod
35

Si vous étendez à partir de ViewPager, vous devez également remplacerexecuteKeyEvent comme indiqué précédemment par @araks

@Override
public boolean executeKeyEvent(KeyEvent event)
{
    return isPagingEnabled ? super.executeKeyEvent(event) : false;
}

Parce que certains appareils comme la Galaxy Tab 4 10 'affichent ces boutons là où la plupart des appareils ne les montrent jamais:

Boutons du clavier

Graisse
la source
50
Samsung bousille toujours les choses pour les développeurs Android.
toobsco42
2
@ toobsco42 Samsung n'est pas le seul dans ce cas. SwiftKey (application clavier populaire) permet aux utilisateurs de placer des flèches sur leur clavier.
Sufian
1
C'est aussi le correctif si vous voulez empêcher quelqu'un d'utiliser un clavier / trackerball de paginer votre pager.
se22as
28

Pour désactiver le balayage

mViewPager.beginFakeDrag();

Pour activer le balayage

mViewPager.endFakeDrag();
KAMAL VERMA
la source
22
Ce n'est pas une bonne solution car elle permet de petites portions de mouvement, du moins dans mon application.
koras
Fonctionne bien pour moi. Quels sont les inconvénients par rapport aux autres solutions proposées?
userM1433372
13

Je devais désactiver le balayage sur une page spécifique et lui donner une belle animation élastique, voici comment:

    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            if (position == MANDATORY_PAGE_LOCATION && positionOffset > 0.5) {
                mViewPager.setCurrentItem(MANDATORY_PAGE_LOCATION, true);
            }
        }
Breed Oded
la source
Il attend que la page suivante soit partiellement visible. Un code pour la page suivante onPageSelectedsera exécuté. Même la page suivante changera. Donc, ce code n'a pas besoin.
CoolMind
13

Je sais qu'il est très tard pour publier ceci, mais voici un petit hack pour atteindre votre résultat;)

Ajoutez simplement une vue factice sous votre viseur:

<android.support.v4.view.ViewPager
     android:layout_width="match_parent"
     android:layout_height="match_parent">
</android.support.v4.view.ViewPager>

<RelativeLayout
     android:id="@+id/dummyView"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
</RelativeLayout>

Ajoutez ensuite un OnClickListenerà votre RelativeLayout.

dummyView = (RelativeLayout) findViewById(R.id.dummyView);

dummyView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
         //Just leave this empty
    }
});

Soyez un peu créatif avec les mises en page, leurs emplacements et leur comportement et vous apprendrez à trouver un moyen de faire absolument tout ce que vous imaginez :)

Bonne chance!

Dinuka Jay
la source
Un moyen plus simple est d'utiliser à la setClickableplace de setOnClickListener, si vous n'avez pas besoin de gérer l' onClickévénement.
Chaos
cela ne bloquerait-il pas également les contacts dans le viseur?
développeur Android
Oui, il sera. C'est le comportement attendu requis par OP @androiddeveloper
Dinuka Jay
@RickGrimesTheCoder Je ne pense pas que vous ayez compris ma question. Je veux dire des vues dans les fragments du viseur. Seront-ils toujours palpables?
développeur Android
Non, ils ne le seront pas, car le visualiseur lui-même dispose d'un écouteur de clics. Cela ne convient que dans les cas où vous n'avez pas d'éléments interactifs dans les fragments. Par exemple, un Welcome ViewPager qui change dynamiquement ses fragments @androiddeveloper
Dinuka Jay
12

J'ai écrit un CustomViewPageravec un contrôle de balayage:

public class ScrollableViewPager extends ViewPager {
    private boolean canScroll = true;
    public ScrollableViewPager(Context context) {
        super(context);
    }
    public ScrollableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public void setCanScroll(boolean canScroll) {
        this.canScroll = canScroll;
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return canScroll && super.onTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return canScroll && super.onInterceptTouchEvent(ev);
    }
}

Si vous définissez canScrollà true, ce ViewPagerpeut être glisser avec le doigt, falseau contraire.

Je l'utilise dans mon projet, et cela fonctionne très bien jusqu'à présent.

L. Swifter
la source
1
Que faire si j'ai un bouton dans le ViewPager et que je veux le cliquer? cette solution arrête tout ce qui se trouve sous le viseur à cliquer.
aimiliano
6

J'ai utilisé cette classe avec succès. La redéfinition de executeKeyEvent est nécessaire pour éviter de glisser à l'aide de flèches sur certains appareils ou pour l'accessibilité:

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class ViewPagerNoSwipe extends ViewPager {
    /**
     * Is swipe enabled
     */
    private boolean enabled;

    public ViewPagerNoSwipe(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = false; // By default swiping is disabled
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return this.enabled ? super.onTouchEvent(event) : false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return this.enabled ? super.onInterceptTouchEvent(event) : false;
    }

    @Override
    public boolean executeKeyEvent(KeyEvent event) {
        return this.enabled ? super.executeKeyEvent(event) : false;
    }

    public void setSwipeEnabled(boolean enabled) {
        this.enabled = enabled;
    }

}

Et dans le xml, appelez-le comme ceci:

<package.path.ViewPagerNoSwipe
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
madx
la source
Ça marche. Seul le balayage est désactivé et un clic sur un onglet est activé. AS avertit que la performClick()méthode n'est pas remplacée.
CoolMind
5

Dans Kotlin, ma solution, combinant les réponses ci-dessus.

class CustomViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
    var swipeEnabled = false

    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        return if (swipeEnabled) super.onTouchEvent(ev) else false
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        return if (swipeEnabled) super.onInterceptTouchEvent(ev) else false
    }

    override fun executeKeyEvent(event: KeyEvent): Boolean {
        return if (swipeEnabled) super.executeKeyEvent(event) else false
    }
}
Jeff Padgett
la source
Le remplacement onInterceptTouchEvent()empêchera les vues enfants de recevoir des entrées. Dans la plupart des cas, ce n'est pas le comportement souhaité.
Alex Semeniuk
J'ai pu interagir avec les vues enfant de chaque fragment. Je ne sais pas de quoi vous parlez.
Jeff Padgett
5

Dans kotlin, nous pouvons résoudre ce problème en créant un widget personnalisé héritant de la classe ViewPager et en ajoutant une valeur d'indicateur pour contrôler le comportement de balayage.

NoSwipePager.kt

class NoSwipePager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) {

    var pagingEnabled: Boolean = false

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return if (this.pagingEnabled) {
            super.onTouchEvent(event)
        } else false
    }

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        return if (this.pagingEnabled) {
            super.onInterceptTouchEvent(event)
        } else false
    }
}

En xml

<your.package.NoSwipePager
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/tab_layout" />

Désactivez le balayage par programmation. Si le kotlin-android-extensionsplugin est appliqué dans build.gradle , le balayage peut être désactivé en écrivant le code ci-dessous.

view_pager.pagingEnabled = false

Sinon, nous pouvons désactiver le balayage à l'aide du code ci-dessous:

val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false
Sagar Chapagain
la source
Le remplacement onInterceptTouchEvent()empêchera les vues enfants de recevoir des entrées. Dans la plupart des cas, ce n'est pas le comportement souhaité.
Alex Semeniuk
@AlexSemeniuk Avez-vous observé un problème après avoir implémenté cela? J'avais activé le glissement sur les éléments de la vue du recycleur pour certaines actions et cela fonctionne bien. Donc, la mise en œuvre fonctionne bien dans mon cas.
Sagar Chapagain
Sagar Chapagain: ou bien sûr, je l'ai fait. Chacune de mes pages contient une vue personnalisée, qui traite les touches de différentes manières (y compris le défilement, le glissement, les tapotements simples et longs). Si vous n'appelez pas, super.onInterceptTouchEvent(event)ces vues ne recevront aucune entrée (ce qui est l'objectif documenté de la onInterceptTouchEventméthode).
Alex Semeniuk
Si tel est le cas, vous devriez plutôt utiliser un fragment enfant et maintenir le backstack.
Sagar Chapagain
En quoi cela est-il pertinent pour la question actuelle? Des fragments sont placés à l'intérieur de certains conteneurs (qui sont des vues ) et leur propre disposition contient des vues . Quel que soit le contenu que j'ai à l'intérieur du ViewPager, je suis toujours confronté au fait que la onInterceptTouchEvent()méthode prioritaire l' empêche (le contenu) de recevoir des entrées.
Alex Semeniuk
4

Essayez de remplacer et de renvoyer true depuis onInterceptTouchEvent () et / ou onTouchEvent () , qui consommera les événements tactiles sur le pager.

AdamK
la source
1
ne voudrait-il pas revenir truepour laisser entendre que l'événement tactile a été géré?
edthethird
1

Une autre solution simple pour désactiver le balayage sur une page spécifique (dans cet exemple, page 2):

int PAGE = 2;
viewPager.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
        if (viewPager.getCurrentItem() == PAGE) {
                viewPager.setCurrentItem(PAGE-1, false);
                viewPager.setCurrentItem(PAGE, false);
                return  true;
        }
        return false;
}
Ofir
la source
1
This worked for me

viewPager.setOnTouchListener(new View.OnTouchListener() {
                                         @Override
                                         public boolean onTouch(View v, MotionEvent event) {
                                             if (viewPager.getCurrentItem() == 0) {
                                                 viewPager.setCurrentItem(-1, false);
                                                 return true;
                                             }
                                             else if (viewPager.getCurrentItem() == 1) {
                                                 viewPager.setCurrentItem(1, false);
                                                 return true;
                                             }
                                             else if (viewPager.getCurrentItem() == 2) {
                                                 viewPager.setCurrentItem(2, false);
                                                 return true;
                                             }
                                             return true;
                                         }
                                     });
Princewill Iroka
la source
1

Si vous écrivez une galerie d'images avec ImageViews et ViewPager, qui prend en charge le zoom et le panoramique, voyez une solution simple décrite ici: Implémentation d'une ImageView zoomable en étendant le ViewPager par défaut dans Phimpme Android (et exemple Github - PhotoView ). Cette solution ne fonctionne pas ViewPagerseule.

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

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        try {
            return super.onInterceptTouchEvent(event);
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
}
CoolMind
la source
1

Si vous utilisez ViewPager2, il vous suffit d'utiliser:

viewpager.setUserInputEnabled(false);

De la documentation :

Activez ou désactivez le défilement initié par l'utilisateur. Cela inclut la saisie tactile (gestes de défilement et de lancer) et la saisie d'accessibilité. La désactivation de la saisie au clavier n'est pas encore prise en charge. Lorsque le défilement initié par l'utilisateur est désactivé, les défilements programmatiques à travers setCurrentItem fonctionnent toujours. Par défaut, le défilement initié par l'utilisateur est activé.

Merci à: https://stackoverflow.com/a/61685871/9026710

Tayyab Mazhar
la source
0

Si vous souhaitez implémenter la même chose pour Android dans Xamarin, voici une traduction en C #

J'ai choisi de nommer l'attribut " ScrollEnabled ". Parce que iOS utilise simplement le même nom excat. Ainsi, vous avez un nom égal sur les deux plates-formes, ce qui facilite la tâche des développeurs.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Android.Util;

namespace YourNameSpace.ViewPackage {

    // Need to disable swiping for ViewPager, if user performs Pre DSA and the dsa is not completed yet
    // http://stackoverflow.com/questions/9650265/how-do-disable-paging-by-swiping-with-finger-in-viewpager-but-still-be-able-to-s
    public class CustomViewPager: ViewPager {
        public bool ScrollEnabled;

        public CustomViewPager(Context context, IAttributeSet attrs) : base(context, attrs) {
            this.ScrollEnabled = true;
        }

        public override bool OnTouchEvent(MotionEvent e) {
            if (this.ScrollEnabled) {
                return base.OnTouchEvent(e);
            }
            return false;
        }

        public override bool OnInterceptTouchEvent(MotionEvent e) {
            if (this.ScrollEnabled) {
                return base.OnInterceptTouchEvent(e);
            }
            return false;
        }

        // For ViewPager inside another ViewPager
        public override bool CanScrollHorizontally(int direction) {
            return this.ScrollEnabled && base.CanScrollHorizontally(direction);
        }

        // Some devices like the Galaxy Tab 4 10' show swipe buttons where most devices never show them
        // So, you could still swipe through the ViewPager with your keyboard keys
        public override bool ExecuteKeyEvent(KeyEvent evt) {
            return this.ScrollEnabled ? base.ExecuteKeyEvent(evt) : false;
        }
    }
}

Dans le fichier .axml:

<?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">
  <YourNameSpace.ViewPackage.CustomViewPager
      android:id="@+id/pager"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@android:color/white"
      android:layout_alignParentTop="true" />
</LinearLayout>
Lepidopteron
la source
0

Aucun des codes ci-dessus ne fonctionne correctement. J'ai essayé ceci

<HorizontalScrollView
                    android:id="@+id/horizontalScrollView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fillViewport="true">

                    <android.support.v4.view.ViewPager
                        android:id="@+id/pager"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent" />
                </HorizontalScrollView>
Nandan Singh
la source
0

voici mon implémentation
que si vous souhaitez désactiver l'animation de balayage, vous pouvez utiliser le swipeListener à gauche et à droite et toujours vouloir le défilement au doigt mais sans animation

ViewpagerMéthode 1-Override onInterceptTouchEventetonTouchEvent

2- Créez le vôtre GestureDetector

3- détecter le geste de glissement et utiliser le setCurrentItem(item, false)

ViewPager

public class ViewPagerNoSwipe extends ViewPager {
    private final GestureDetector gestureDetector;
    private OnSwipeListener mOnSwipeListener;

    public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
        mOnSwipeListener = onSwipeListener;
    }

    public ViewPagerNoSwipe(@NonNull Context context) {
        super(context);
        gestureDetector = new GestureDetector(context, new GestureListener());

    }

    public ViewPagerNoSwipe(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        gestureDetector = new GestureDetector(context, new GestureListener());


    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        gestureDetector.onTouchEvent(ev);
        return false;
    }

    public class GestureListener extends GestureDetector.SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeRight();
                        } else {
                            if(mOnSwipeListener!=null)
                                mOnSwipeListener.onSwipeLeft();
                        }
                        result = true;
                    }
                } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeBottom();
                    } else {
                        if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeTop();
                    }
                    result = true;
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }

    public interface OnSwipeListener {

         void onSwipeRight();

        void onSwipeLeft();

        void onSwipeTop();

        void onSwipeBottom();
    }
}

le lorsque vous êtes configuré le ViewPager définir le swipeListener

postsPager.setOnSwipeListener(new ViewPagerNoSwipe.OnSwipeListener() {
            @Override
            public void onSwipeRight() {

              postsPager.setCurrentItem(postsPager.getCurrentItem() + 1,false);

            }

            @Override
            public void onSwipeLeft() {

            postsPager.setCurrentItem(postsPager.getCurrentItem() - 1, false);

            }
             ...
           }
tamtom
la source
0

Je viens de personnaliser un peu le viseur et de désactiver facilement le balayage.

public class CustomViewPager extends ViewPager {

private boolean swipeLocked;

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

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

public boolean getSwipeLocked() {
    return swipeLocked;
}

public void setSwipeLocked(boolean swipeLocked) {
    this.swipeLocked = swipeLocked;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return !swipeLocked && super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return !swipeLocked && super.onInterceptTouchEvent(event);
}

@Override
public boolean canScrollHorizontally(int direction) {
    return !swipeLocked && super.canScrollHorizontally(direction);
}
}
Shivam Yadav
la source
-1
shareViewPager?.setOnTouchListener(object :View.OnTouchListener{
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                for (PAGE in 0..shareViewPager.adapter!!.count){
                    if (shareViewPager.currentItem==PAGE){
                        shareViewPager.setCurrentItem(PAGE-1,false)
                        shareViewPager.setCurrentItem(PAGE,false)
                    }}
                return true
            }

        })
Cihat Baydan
la source