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

我有ViewPager,在它下面我有10个按钮。通过单击按钮,例如#4,寻呼机立即转到mPager.setCurrentItem(3);的第#4页。但是,我想通过水平滑动手指禁用分页。因此,通过单击按钮来完成分页只有。 那么,我如何禁用手指滑动?< / p >
380998 次浏览

尝试覆盖并从onInterceptTouchEvent ()和/或onTouchEvent ()中返回true,这将消耗分页器上的触摸事件。

你需要子类ViewPageronTouchEvent有很多你不想改变的好东西,比如允许子视图获得触摸。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.
*/

这里有一个完整的解决方案:

首先,把这个类添加到你的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();方法用于平滑过渡

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

mPager.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
return true;
}
});
ViewPager更通用的扩展是创建一个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;
}
}

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

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

你只需要用false调用setPagingEnabled方法,用户就不能滑动来分页了。

最好声明它是可样式的,这样你就可以从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;
}

在values/attr.xml中:

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

这样你就可以在你的布局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" />

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

我需要禁用一个特定页面上的滑动,并给它一个漂亮的橡皮筋动画,以下是如何:

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

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

如果ViewPager本身在另一个ViewPager中,只覆盖onTouchEventonInterceptTouchEvent是不够的。子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();

我写了一个带有滑动控件的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可以用手指滑动,false则相反。

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

我知道现在发表这篇文章有点晚了,但这里有一个小技巧可以达到你的结果;)

简单地添加一个虚拟视图下面你的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>

然后添加OnClickListenerRelativeLayout

dummyView = (RelativeLayout) findViewById(R.id.dummyView);


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

获得一点创意的布局,他们的位置和他们的行为,你会学会找到一种方法来做任何你想象的事情:)

好运!

如果你从ViewPager扩展,你还必须重写executeKeyEvent,正如之前@araks指出的那样

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

因为一些设备,比如Galaxy Tab 4 10'显示了这些大多数设备从未显示过的按钮:

Keyboard buttons

如果你想在Xamarin中为Android实现同样的功能,这里有一个c#的翻译

我选择将属性命名为“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>

如果你用ImageViews和ViewPager写一个图库,它支持缩放和平移,可以看到这里描述的一个简单的解决方案:通过扩展Phimpme Android中的默认ViewPager实现一个可缩放的ImageView(和Github样本- PhotoView)。这个解决方案不能单独使用ViewPager

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

上面的代码都不能正常工作。我试过了

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

我成功地使用了这门课。覆盖executeKeyEvent是为了避免在某些设备中使用箭头或为了可访问性:

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


}

xml中这样调用它:

<package.path.ViewPagerNoSwipe
android:layout_width="match_parent"
android:layout_height="match_parent" />
这里是我的实现
如果你想禁用滑动动画,你可以左右使用swipeListener,仍然希望通过手指滚动,但没有动画

1-覆盖Viewpager方法onInterceptTouchEventonTouchEvent

2-创建自己的GestureDetector

3-检测滑动手势并使用setCurrentItem(item, false)

: viewpage

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

当你设置ViewPager时,设置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);


}
...
}

我只是自定义了viewpager一点和禁用滑动容易。

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

现在我们不需要创建自定义的ViewPager

一个新的<强> # EYZ0 < / >强名称视图在android中可用

垂直方向支持 .

  • 除了传统的水平分页之外,ViewPager2还支持垂直分页。通过设置android:orientation属性,可以为ViewPager2元素启用垂直分页

使用XML

<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />

使用代码

禁用在viewpager2使用滑动

viewPager2.setUserInputEnabled(false);

viewpager2使用中启用滑动

viewPager2.setUserInputEnabled(true);

要了解更多信息,请查看这个

更新

shareViewPager?.setOnTouchListener(object :View.OnTouchListener{
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
for (PAGE in 0..shareViewPager.adapter!!.count){
if (shareViewPager.currentItem==PAGE){
shareViewPager.setCurrentItem(PAGE-1,false)
shareViewPager.setCurrentItem(PAGE,false)
}}
return true
}


})

在Kotlin,我的解决方案,结合上述答案。

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

在kotlin中,我们可以通过创建一个继承ViewPager类的自定义小部件并添加一个用于控制滑动行为的标志值来解决这个问题。

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

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

以编程方式禁用滑动。如果kotlin-android-extensions插件应用在build.gradle中,可以通过编写下面的代码禁用滑动。

view_pager.pagingEnabled = false

否则,我们可以使用下面的代码禁用滑动:

val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false

如果你使用的是ViewPager2,你只需要使用:

# EYZ0

文档:

启用或禁用用户主动滚动。这包括触摸输入(滚动和投掷手势)和可访问性输入。目前还不支持禁用键盘输入。当用户发起的滚动被禁用时,通过setCurrentItem进行的编程滚动仍然有效。默认情况下,用户主动滚动是启用的。

感谢:https://stackoverflow.com/a/61685871/9026710

在芬兰湾的科特林

viewPagerNavigation.isUserInputEnabled = false
* NonSwipebleViewPager for kotlin
    

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.animation.DecelerateInterpolator
import android.widget.Scroller
import androidx.viewpager.widget.ViewPager
import java.lang.reflect.Field




class NonSwipebleViewPager : ViewPager {
constructor(context: Context?) : super(context!!) {
setMyScroller()
}


constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {
setMyScroller()
}


override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
return false
}


override fun onTouchEvent(event: MotionEvent): Boolean {
return false
}


private fun setMyScroller() {
try {
val viewpager: Class<*> = ViewPager::class.java
val scroller: Field = viewpager.getDeclaredField("mScroller")
scroller.isAccessible = true
scroller.set(this, MyScroller(context))
} catch (e: Exception) {
e.printStackTrace()
}
}


inner class MyScroller(context: Context?) :
Scroller(context, DecelerateInterpolator()) {
override fun startScroll(
startX: Int,
startY: Int,
dx: Int,
dy: Int,
duration: Int
) {
super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/)
}
}
}

如果你不想要任何类型的滚动水平或垂直从用户的手指,那么你可以尝试-

yourViewPager.isUserInputEnabled = false

使用“isUserInputEnabled”。