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?
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
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.
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;
}
});
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.
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);
}
}
Pour désactiver le balayage
mViewPager.beginFakeDrag();
pour activer le balayage
mViewPager.endFakeDrag();
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:
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);
}
}
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!
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.
Essayez de remplacement et de retourner true soit à partir d' onInterceptTouchEvent() et/ou onTouchEvent() , qui consomment les événements tactiles sur le pager.
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;
}
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>
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;
}
});
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;
}
}
}
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>
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" />