【发布时间】:2011-10-18 21:32:17
【问题描述】:
我有一个ViewPager,它实例化了一个View。我想在将搜索结果返回到视图时暂时禁用 viewpager 和子按钮的滚动。我打电话给viewPager.setEnabled(false),但这并没有禁用它。
有人有什么想法吗?
【问题讨论】:
我有一个ViewPager,它实例化了一个View。我想在将搜索结果返回到视图时暂时禁用 viewpager 和子按钮的滚动。我打电话给viewPager.setEnabled(false),但这并没有禁用它。
有人有什么想法吗?
【问题讨论】:
一个简单的解决方案是创建您自己的ViewPager 子类,它具有private boolean 标志isPagingEnabled。然后覆盖onTouchEvent 和onInterceptTouchEvent 方法。如果isPagingEnabled 等于true,则调用super 方法,否则return。
public class CustomViewPager extends ViewPager {
private boolean isPagingEnabled = true;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onInterceptTouchEvent(event);
}
public void setPagingEnabled(boolean b) {
this.isPagingEnabled = b;
}
}
然后在您的Layout.XML 文件中将任何<com.android.support.V4.ViewPager> 标记替换为<com.yourpackage.CustomViewPager> 标记。
此代码改编自此blog post。
【讨论】:
有一个简单的解决方法:
当你想禁用 viewpager 滚动时:
mViewPager.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent arg1) {
return true;
}
});
当你想重新启用它时:
mViewPager.setOnTouchListener(null);
这样就可以了。
【讨论】:
这是我对 slayton 答案的轻量级变体:
public class DeactivatableViewPager extends ViewPager {
public DeactivatableViewPager(Context context) {
super(context);
}
public DeactivatableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return !isEnabled() || super.onTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return isEnabled() && super.onInterceptTouchEvent(event);
}
}
使用我的代码,您可以使用setEnable() 禁用分页。
【讨论】:
onInterceptTouchEvent() 将阻止子视图接收输入。在大多数情况下,这不是预期的行为。
我找到了一个简单的解决方案。
//disable swiping
mViewPager.beginFakeDrag();
//enable swiping
mViewPager.endFakeDrag();
【讨论】:
我建议另一种方法来解决这个问题。这个想法是用一个scrollView包装你的viewPager,这样当这个scrollView不可滚动时,你的viewPager也是不可滚动的。
这是我的 XML 布局:
<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/viewPager"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</HorizontalScrollView>
无需代码。
对我来说很好。
【讨论】:
在我使用 ViewPager 2 alpha 2 的情况下,下面的 sn-p 可以工作
viewPager.isUserInputEnabled = false
能够禁用用户输入(setUserInputEnabled、isUserInputEnabled)
更多viewpager2 1.0.0-alpha02变化参考这里
最新版本 ViewPager 2 alpha 4 也进行了一些更改
orientation 和 isUserScrollable 属性不再是 SavedState 的一部分
更多viewpager2#1.0.0-alpha04变化参考这里
【讨论】:
禁用滑动
mViewPager.beginFakeDrag();
启用滑动
mViewPager.endFakeDrag();
【讨论】:
最适合我的解决方案是:
public class DeactivatedViewPager extends ViewPager {
public DeactivatedViewPager (Context context) {
super(context);
}
public DeactivatedViewPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean canScrollHorizontally(int direction) {
return false;
}
}
在此之后,滚动将被触摸禁用,然后您仍然可以使用setCurrentItem 方法更改页面。
【讨论】:
canScrollHorizontally() 方法在当前场景下无效。滑动发生时甚至不会调用它。
这是 Kotlin 和 androidX 中的答案
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.viewpager.widget.ViewPager
class DeactivatedViewPager @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : ViewPager(context, attrs) {
var isPagingEnabled = true
override fun onTouchEvent(ev: MotionEvent?): Boolean {
return isPagingEnabled && super.onTouchEvent(ev)
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return isPagingEnabled && super.onInterceptTouchEvent(ev)
}
}
【讨论】:
这个怎么样:
我用CustomViewPager
接下来,覆盖 scrollTo 方法
我在进行大量小滑动时检查了移动,它不会滚动到其他页面。
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;
}
@Override
public void scrollTo(int x, int y) {
if(enabled) {
super.scrollTo(x, y);
}
}
}
【讨论】:
View.scrollTo(int x, int y) 为我解决了这个问题。 谢谢
我创建了一个基于从 Java 转换此答案的 Kotlin 版本:https://stackoverflow.com/a/13437997/8023278
没有内置的方法来禁用 ViewPager 的页面之间的滑动,需要的是 ViewPager 的扩展,它覆盖 onTouchEvent 和 onInterceptTouchEvent 以防止滑动操作。为了使其更通用,我们可以添加一个方法 setSwipePagingEnabled 来启用/禁用页面之间的滑动。
class SwipeLockableViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
private var swipeEnabled = false
override fun onTouchEvent(event: MotionEvent): Boolean {
return when (swipeEnabled) {
true -> super.onTouchEvent(event)
false -> false
}
}
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return when (swipeEnabled) {
true -> super.onInterceptTouchEvent(event)
false -> false
}
}
fun setSwipePagingEnabled(swipeEnabled: Boolean) {
this.swipeEnabled = swipeEnabled
}
}
然后在我们的布局 xml 中,我们使用新的 SwipeLockableViewPager 而不是标准的 ViewPager
<mypackage.SwipeLockableViewPager
android:id="@+id/myViewPager"
android:layout_height="match_parent"
android:layout_width="match_parent" />
现在在我们的活动/片段中,我们可以调用myViewPager.setSwipePagingEnabled(false),用户将无法在页面之间滑动
更新
截至 2020 年,我们现在拥有 ViewPager2。如果你 migrate 到 ViewPager2 有一个内置的方法来禁用刷卡:myViewPager2.isUserInputEnabled = false
【讨论】:
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);
}
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// stop swipe
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// stop switching pages
return false;
}
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*/);
}
}
}
然后在您的 Layout.XML 文件中替换任何 --- com.android.support.V4.ViewPager --- 带有 --- com.yourpackage.NonSwipeableViewPager --- 标签的标签。
相同的解决方案,但在 Kotlin 中:
class NonSwipeableViewPager constructor(
context: Context,
attrs: AttributeSet?
) : ViewPager(context, attrs) {
private var isPagingEnabled = true
override fun onTouchEvent(event: MotionEvent?): Boolean {
return isPagingEnabled && super.onTouchEvent(event)
}
override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
return isPagingEnabled && super.onInterceptTouchEvent(event)
}
fun setPagingEnabled(isEnabled: Boolean) {
isPagingEnabled = isEnabled
}
}
【讨论】:
slayton 的答案很好用。 如果你想停止像猴子一样滑动,你可以用
覆盖 OnPageChangeListener@Override public void onPageScrollStateChanged(final int state) {
switch (state) {
case ViewPager.SCROLL_STATE_SETTLING:
mPager.setPagingEnabled(false);
break;
case ViewPager.SCROLL_STATE_IDLE:
mPager.setPagingEnabled(true);
break;
}
}
所以你只能并排滑动
【讨论】:
setPagingEnabled() 方法的作用。请附上完整的代码。
来自 androidx 的新类 ViewPager2 允许使用 setUserInputEnabled(false) 方法禁用滚动
private val pager: ViewPager2 by bindView(R.id.pager)
override fun onCreate(savedInstanceState: Bundle?) {
pager.isUserInputEnabled = false
}
【讨论】:
//禁用viewpager滚动的解决方案
viewPager.beginFakeDrag();
【讨论】: