Comment désactiver la pagination en glissant avec le doigt dans le ViewPager tout en étant capable de glisser programmatiquement?

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

427
demandé sur theateist 2012-03-11 01:18:36

17 réponses

vous devez sous-classe ViewPager. onTouchEvent a beaucoup de bonnes choses en elle que vous ne voulez pas changer, comme permettre aux opinions de l'enfant pour obtenir des touches. onInterceptTouchEvent 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 dossier src:

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 du ViewPager habituel, que vous avez probablement spécifié comme android.soutien.v4.vue.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 LinearLayout et est destiné à prendre la totalité de l'écran, c'est pourquoi layout_weight est 1 et layout_height est 0dp.

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

769
répondu louielouie 2016-08-17 04:52:24

l'extension plus générale de ViewPager serait de créer une méthode SetPagingEnabled afin que nous puissions activer et désactiver la pagination à la volée. Pour activer / désactiver le swiping, un peu plus de deux méthodes: onTouchEvent et onInterceptTouchEvent . Tous les deux retourneront "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;
    } 
}

puis sélectionnez ceci à la place du viewpager intégré en XML

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

vous avez juste besoin d'appeler la méthode setPagingEnabled avec false et les utilisateurs ne pourront pas glisser vers paginer.

408
répondu Rajul 2017-03-08 18:51:37

la façon la plus simple est de setOnTouchListener et de retourner true pour ViewPager .

mPager.setOnTouchListener(new OnTouchListener()
    {           
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            return true;
        }
    });
90
répondu Wayne 2016-09-27 12:45:46

mieux de le déclarer styleable, de sorte que 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>

pour 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.

51
répondu Pietro 2013-09-08 12:54:07

impératif que onTouchEvent et onInterceptTouchEvent n'est pas suffisante dans le cas où vous avez ViewPager lui-même à l'intérieur d'un autre ViewPager. Child ViewPager volerait les événements horizontal scroll touch de parent ViewPager à moins qu'il ne soit placé sur sa première / dernière page.

pour que cette configuration fonctionne correctement, vous devez aussi outrepasser la méthode canScrollHorizontally .

Voir LockableViewPager mise en œuvre 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);
    }

}
42
répondu sidon 2017-10-31 09:22:21

Pour désactiver le balayage

mViewPager.beginFakeDrag();

pour activer le balayage

mViewPager.endFakeDrag();
24
répondu KAMAL VERMA 2016-09-27 12:45:22

si vous prolongez de ViewPager, vous devez aussi remplacer executeKeyEvent comme indiqué précédemment par @araks

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

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

Keyboard buttons

23
répondu Grease 2016-08-01 18:16:29

j'ai dû désactiver swiping 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);
            }
        }
13
répondu WhereDatApp.com 2015-06-26 21:07:28

je sais que c'est très tard pour poster cela, mais voici un petit hack pour atteindre vos objectifs ;)

il suffit D'ajouter une vue de mannequin en dessous de votre plan de vision:

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

puis Ajouter 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 placements et leur comportement et vous apprendrez à trouver un moyen de faire absolument tout ce que vous imaginez:)

bonne chance!

11
répondu Dinuka 2016-09-27 12:45:07

j'ai écrit un CustomViewPager avec un contrôle de swiping:

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 mettez canScroll à true , ce ViewPager peut être glissé avec le doigt, false au contraire.

Je l'utilise dans mon projet, et ça marche très bien jusqu'à maintenant.

8
répondu L. Swifter 2016-04-20 14:47:47

Essayez de remplacement et de retourner true soit à partir d' onInterceptTouchEvent() et/ou onTouchEvent() , qui consomment les événements tactiles sur le pager.

4
répondu AdamK 2012-03-10 23:10:04

une autre solution facile pour désactiver le balayage à 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;
}
1
répondu Ofir 2015-12-01 04:48:46

si vous voulez mettre en œuvre 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 le même nom excat. Donc, vous avez le même nom à travers les deux plates-formes, ce qui rend plus facile pour les 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
    // /q/how-do-disable-paging-by-swiping-with-finger-in-viewpager-but-still-be-able-to-swipe-programmatically-21145/"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>
0
répondu Lepidopteron 2017-05-03 07:14:18
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;
                                         }
                                     });
0
répondu Princewill Iroka 2018-03-01 18:00:35

une solution simple est décrite ici: implémenter une vue ImageView zoomable en prolongeant le ViewPager par défaut dans Phimpme Android (et GitHub sample - PhotoView ):

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;
        }
    }
}
0
répondu CoolMind 2018-03-15 11:30:29

aucun des codes ci-dessus ne fonctionne correctement.j'ai essayé ce

<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>
0
répondu Nandan Singh 2018-04-06 14:07:22

j'ai utilisé cette classe avec succès. Le executeKeyEvent est nécessaire pour éviter de glisser des flèches dans 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" />
0
répondu madx 2018-08-10 22:27:42