如何通过在ViewPager中用手指滑动禁用分页,但仍然能够以编程方式刷卡?

我有ViewPager和它下面我有10个button。 通过点击button,例如#4,寻呼机立即通过mPager.setCurrentItem(3);立即进入第4页mPager.setCurrentItem(3); 。 但是,我想用手指水平滑动来禁用分页。 因此,只需点击button即可完成分页。 那么,我怎样才能禁用用手指划动?

您需要inheritanceViewPager。 onTouchEvent有很多好东西,你不想改变,比如允许子视图触摸。 onInterceptTouchEvent是你想要改变的。 如果您查看ViewPager的代码,您将看到注释:

  /* * 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. */ 

这是一个完整的解决scheme:

首先,将这个类添加到你的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*/); } } } 

接下来,请确保使用此类而不是常规的ViewPager,您可能将其指定为android.support.v4.view.ViewPager。 在你的布局文件中,你要用类似的方式指定它:

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

这个特殊的例子是在一个LinearLayout中,它意味着占用整个屏幕,这就是为什么layout_weight是1而layout_height是0dp的原因。

setMyScroller(); 方法是平滑过渡

ViewPager的更一般的扩展是创build一个SetPagingEnabled方法,以便我们可以在运行中启用和禁用分页。 要启用/禁用滑动,只需覆盖两个方法: onTouchEventonInterceptTouchEvent 。 如果分页被禁用,两者都将返回“false”。

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

然后select这个而不是XML中的内置viewpager

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

你只需要用false调用setPagingEnabled方法,用户将不能滑动到分页。

最简单的方法是setOnTouchListener并为ViewPager返回true

 mPager.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return true; } }); 

更好的声明它的风格,所以你可以改变它的属性从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; } 

并在你的值/ attr.xml中:

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

所以你可以在你的布局中使用它:

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

当然,你仍然可以有一个get / set属性。

如果您将ViewPager本身放在另一个ViewPager中,则仅覆盖onTouchEventonInterceptTouchEvent是不够的。 Child ViewPager会从父ViewPager中窃取水平滚动触摸事件,除非它位于第一页/最后一页。

要使此设置正常工作,您还需要覆盖canScrollHorizontally方法。

请参阅下面的LockableViewPager实现。

 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); } } 

禁用滑动

 mViewPager.beginFakeDrag(); 

启用滑动

 mViewPager.endFakeDrag(); 

我需要禁用一个特定的页面上的滑动,并给它一个很好的橡皮筋animation,这是如何:

  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); } } 

如果您是从ViewPager进行扩展, 那么您还必须按照以前的@araks指示的方式覆盖 executeKeyEvent

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

因为像Galaxy Tab 4 10'这样的设备显示了大多数设备从不显示的button:

键盘按钮

我知道这是很晚才能发布这个,但这是一个小小的黑客来实现你的结果;)

只需在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> 

然后添加一个OnClickListener到你的RelativeLayout

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

通过布局,布局和行为来获得一点创意,您将学会find一种方法来完成您想象中的任何事情:)

祝你好运!

我用一个滑动控件写了一个CustomViewPager

 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); } } 

如果将canScroll设置为true ,则此ViewPager可以用手指滑动,反之ViewPager false

我在我的项目中使用这个,直到现在它工作得很好。

尝试重写并从onInterceptTouchEvent()和/或onTouchEvent()返回true,这将消耗传呼机上的触摸事件。

另一个简单的解决scheme,禁用特定页面的滑动(在本例中为第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; } 

如果你想在Xamarin中实现相同的Android,这里是一个翻译到C#

我select了命名属性“ ScrollEnabled ”。 因为iOS只使用相同的命名。 所以,在两个平台上你都有相同的命名,使开发人员更容易。

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

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