android - stop - ¿Cómo deshabilitar la paginación al deslizar con el dedo en ViewPager pero aún así se puede deslizar programáticamente?
disable swipe viewpager (17)
Es mejor declararlo con estilo, para que pueda cambiar su propiedad 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;
}
Y en tus valores / attr.xml:
<declare-styleable name="MyViewPager">
<attr name="swipeable" format="boolean" />
</declare-styleable>
para que puedas usarlo en tu layout 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" />
Por supuesto, todavía puede tener una propiedad get / set.
Tengo ViewPager y debajo tengo 10 botones. Al hacer clic en el botón, por ejemplo # 4, el buscapersonas pasa inmediatamente a la página # 4 por mPager.setCurrentItem(3);
. Pero, quiero deshabilitar la paginación deslizando con el dedo horizontalmente. Por lo tanto, la paginación se realiza SOLAMENTE haciendo clic en los botones. Entonces, ¿cómo puedo desactivar el deslizar con el dedo?
Escribí un CustomViewPager
con un control de deslizamiento:
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 establece canScroll
en true
, este ViewPager
puede ViewPager
con el dedo, por el contrario, false
.
Utilizo esto en mi proyecto, y funciona muy bien hasta ahora.
Intente anular y devolver verdadero desde onInterceptTouchEvent() y / o onTouchEvent() , que consumirá eventos táctiles en el paginador.
La extensión más general de ViewPager
sería crear un método SetPagingEnabled
para que podamos habilitar y deshabilitar la paginación sobre la marcha. Para habilitar / deshabilitar el deslizamiento, simplemente anule dos métodos: onTouchEvent
y onInterceptTouchEvent
. Ambos devolverán "falso" si la paginación fue deshabilitada.
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;
}
}
Luego seleccione esto en lugar del viewpager incorporado en XML
<mypackage.CustomViewPager
android:id="@+id/myViewPager"
android:layout_height="match_parent"
android:layout_width="match_parent" />
Solo necesita llamar al método setPagingEnabled
con false
y los usuarios no podrán deslizarse para paginar.
La forma más sencilla es setOnTouchListener
y devolver true
para ViewPager
.
mPager.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
return true;
}
});
Necesitaba deshabilitar el deslizamiento en una página específica, y darle una buena animación de banda elástica, así es como:
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);
}
}
Necesitas subclasificar ViewPager. onTouchEvent tiene muchas cosas buenas que no quieres cambiar, como permitir que las vistas de los niños reciban toques. onInterceptTouchEvent es lo que quieres cambiar. Si miras el código de ViewPager, verás el comentario:
/*
* 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.
*/
Aquí hay una solución completa:
Primero, agregue esta clase a su carpeta 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*/);
}
}
}
A continuación, asegúrese de usar esta clase en lugar del ViewPager normal, que probablemente haya especificado como android.support.v4.view.ViewPager. En su archivo de diseño, querrá especificarlo con algo como:
<com.yourcompany.NonSwipeableViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
Este ejemplo en particular está en un LinearLayout y está destinado a ocupar toda la pantalla, por lo que layout_weight es 1 y layout_height es 0dp.
Y setMyScroller (); el metodo es para una transicion suave
Ninguno de los códigos anteriores funciona correctamente. Lo he intentado.
<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>
Otra solución fácil para desactivar el deslizamiento en una página específica (en este ejemplo, página 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;
}
Para desactivar el deslizamiento
mViewPager.beginFakeDrag();
Para habilitar el deslizamiento
mViewPager.endFakeDrag();
Sé que es muy tarde para publicar esto, pero aquí hay un pequeño truco para lograr tu resultado;)
Simplemente agregue una vista ficticia debajo de su 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>
Luego, agregue un OnClickListener
a su RelativeLayout
.
dummyView = (RelativeLayout) findViewById(R.id.dummyView);
dummyView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Just leave this empty
}
});
Sea un poco creativo con los diseños, sus ubicaciones y su comportamiento, y aprenderá a encontrar la manera de hacer absolutamente todo lo que imagina :)
¡Buena suerte!
Si desea implementar lo mismo para Android en Xamarin, aquí hay una traducción a C #
Elegí nombrar el atributo " ScrollEnabled ". Porque iOS solo usa el mismo nombre de excat. Por lo tanto, tiene el mismo nombre en ambas plataformas, lo hace más fácil para los desarrolladores.
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://.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 el archivo .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>
Si se está extendiendo desde ViewPager, también debe anular executeKeyEvent
como se indicó anteriormente en @araks
@Override
public boolean executeKeyEvent(KeyEvent event)
{
return isPagingEnabled ? super.executeKeyEvent(event) : false;
}
Debido a que algunos dispositivos como el Galaxy Tab 4 10 ''muestran estos botones donde la mayoría de los dispositivos nunca los muestran:
Una solución simple se describe aquí: Implementar un ImageView con zoom extendiendo el ViewPager predeterminado en Phimpme Android (y muestra de Github - 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;
}
}
}
Utilicé esta clase con éxito. Se requiere anular el executeKeyEvent para evitar el deslizamiento usando flechas en algunos dispositivos o para accesibilidad:
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;
}
}
Y en el xml llámalo así:
<package.path.ViewPagerNoSwipe
android:layout_width="match_parent"
android:layout_height="match_parent" />
onTouchEvent
solo onTouchEvent
y onInterceptTouchEvent
no es suficiente en caso de que tenga ViewPager dentro de otro ViewPager. Child ViewPager robaría eventos táctiles de desplazamiento horizontal de ViewPager principal a menos que se coloque en su primera / última página.
Para que esta configuración funcione correctamente, también debe anular el método canScrollHorizontally
.
Vea la implementación de LockableViewPager
continuación.
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);
}
}
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;
}
});