J'ai ViewPager et en dessous, j'ai 10 boutons. En cliquant sur le bouton, par exemple # 4, le téléavertisseur passe immédiatement à la page # 4 de mPager.setCurrentItem(3);
. Mais, je veux désactiver la pagination en faisant glisser le doigt horizontalement. Ainsi, la recherche est effectuéeUNIQUEMENTen cliquant sur les boutons. Alors, comment puis-je désactiver le balayage avec le doigt?
Vous devez sous-classer ViewPager
. onTouchEvent
contient beaucoup de bonnes choses que vous ne voulez pas changer, comme permettre aux vues enfants d'obtenir des contacts. 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, veillez à utiliser cette classe à la place de la valeur normale ViewPager
, que vous avez probablement spécifiée sous la forme 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 LinearLayout
et est censé occuper tout l'écran, raison pour laquelle layout_weight
est 1 et layout_height
est 0dp.
AndsetMyScroller();
met en oeuvre une transition en douceur
L’extension plus générale de ViewPager
consisterait à créer une méthode SetPagingEnabled
afin que nous puissions activer et désactiver la pagination à la volée . Pour activer/désactiver le balayage, il suffit de remplacer deux méthodes: onTouchEvent
et onInterceptTouchEvent
. Les deux renverront "faux" 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;
}
}
Ensuite, sélectionnez 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 méthode setPagingEnabled
avec false
et les utilisateurs ne pourront pas balayer pour paginer.
Le moyen le 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 vaut le déclarer stylable pour pouvoir 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.
Remplacer uniquement onTouchEvent
et onInterceptTouchEvent
n'est pas suffisant si ViewPager est lui-même dans un autre ViewPager. ViewPager enfant volerait des événements tactiles de défilement horizontal à partir de ViewPager parent à moins qu’il ne soit positionné sur sa première/dernière page.
Pour que cette installation fonctionne correctement, vous devez également remplacer la méthode canScrollHorizontally
.
Voir LockableViewPager
implé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);
}
}
Pour désactiver le balayage
mViewPager.beginFakeDrag();
Pour activer le balayage
mViewPager.endFakeDrag();
Si vous étendez à partir de ViewPager, vous devez également remplacer executeKeyEvent
comme indiqué précédemment par @araks
@Override
public boolean executeKeyEvent(KeyEvent event)
{
return isPagingEnabled ? super.executeKeyEvent(event) : false;
}
Certains appareils, comme le Galaxy Tab 4 10 ', affichent ces boutons là où la plupart des appareils ne les affichent jamais:
Je devais désactiver le balayage sur une page spécifique et lui donner une animation en caoutchouc, 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 qu'il est très tard pour poster ceci, mais voici un petit bidouillage pour obtenir votre résultat;)
Ajoutez simplement une vue fictive ci-dessous votre viewpager:
<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 une 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 créatif avec les mises en page, leurs emplacements et leur comportement et vous apprendrez à trouver le moyen de faire absolument tout ce que vous imaginez :)
Bonne chance!
J'ai écrit une CustomViewPager
avec 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
sur true
, cette ViewPager
peut glisser avec le doigt, false
au contraire.
J'utilise cela dans mon projet et cela fonctionne très bien jusqu'à maintenant.
Essayez de remplacer et de renvoyer true à partir de onInterceptTouchEvent () et/ou onTouchEvent () , qui consommera des événements tactiles sur le pageur.
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 du 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ésactiver le balayage par programmation. Si le plugin kotlin-Android-extensions
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 en utilisant le code ci-dessous:
val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false
Maintenant, nous n’avons plus besoin de créer une ViewPager
personnalisée
Une nouvelle vue ViewPager2
name disponible sous Android
Pour désactiver le balayage dans viewpager2
, utilisez
viewPager2.setUserInputEnabled(false);
Pour activer le balayage dans viewpager2
, utilisez
viewPager2.setUserInputEnabled(true);
pour plus d'informations vérifier ceci
J'ai utilisé cette classe avec succès. Le remplacement de executeKeyEvent est requis pour éviter de glisser à l'aide de flèches sur certains périphériques ou pour des raisons d'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" />
Si vous écrivez une galerie d'images avec ImageView
s et ViewPager
, qui prend en charge le zoom et le panoramique, voir une solution simple décrite ici: Implémentation d'un ImageView zoomable en étendant le ViewPager par défaut dans Phimpme Android (et exemple Github - PhotoView ). Cette solution ne fonctionne pas avec ViewPager
seule.
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;
}
}
}
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, les noms sont identiques 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;
}
}
}
En 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>
Une autre solution facile 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;
}
Je viens de personnaliser un peu le viewpager 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);
}
}
voici ma mise en oeuvre
que si vous voulez désactiver l’animation par balayage, vous pouvez utiliser le glissementListener à gauche et à droite et toujours vouloir le défilement par doigt mais sans animation
1 méthode de substitution Viewpager
méthode onInterceptTouchEvent
et onTouchEvent
2- créer votre propre GestureDetector
3- détectez le geste de balayage et utilisez 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();
}
}
lorsque vous configurez ViewPager, définissez 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);
}
...
}
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
}
}
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;
}
});
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>