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

Posted

技术标签:

【中文标题】如何通过在 ViewPager 中用手指滑动来禁用分页但仍然能够以编程方式滑动?【英文标题】:How do disable paging by swiping with finger in ViewPager but still be able to swipe programmatically? 【发布时间】:2012-03-27 20:39:19 【问题描述】:

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

【问题讨论】:

首先使用ViewFlipper 怎么样?它将为您省去很多麻烦。 使用 ViewPager2,禁用滑动只需一行代码:***.com/questions/54978846/… 【参考方案1】:

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

【讨论】:

难道他不想返回true 来暗示触摸事件已被处理吗?【参考方案2】:

您需要继承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_
    android:layout_
    android:layout_weight="1" />

这个特殊的例子在LinearLayout 中,是为了占据整个屏幕,这就是为什么layout_weight 是1 而layout_height 是0dp。

setMyScroller();方法是为了平滑过渡

【讨论】:

@louielouie 顺便说一句:有什么特别的原因,为什么您选择0dp height/1 weight 解决方案而不是match_parent height 来实现全屏效果?这样做是否会提高性能? 此答案不会阻止使用键盘左/右键时的页面滑动(在模拟器中尝试)。对于触摸设备来说可能不是问题,但对于电视和笔记本电脑来说可能是一个问题。 @MarvinLabs @Thorbear 通过键盘禁用页面滚动的正确方法是覆盖executeKeyEvent()。这是随后调用allowScroll() 的方法。 // Never allow swiping by keyboard LEFT, RIGHT, TAB and SHIFT+TAB keys@Override public boolean executeKeyEvent(KeyEvent event) return false; 好吧,这也禁用了垂直滚动...这很糟糕,如果您使用的是列表视图。 我希望谷歌可以提供一种方法,我们提供我们的界面方法来处理触摸/滑动,因为我相信它不会受到伤害?【参考方案3】:

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

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

【讨论】:

有时不起作用。我正在使用带有 FragmentPagerAdapter 和几个 Fragment 的 ViewPager 。将 OnTouchListener 设置为 pager 后,如果我向左一甩,UI 仍然会向左移动一点。 在返回true之前添加pager.setCurrentItem(pager.getCurrentItem());时有效。 似乎对我有用。为了解决一些布局故障,我的适配器中有public int getItemPosition(Object object) return POSITION_NONE; ,这会强制重新创建页面并可能也解决其他问题。 这是一个部分有效的解决方案。水平滑动以某种奇怪的方式处理。作为 ViewPager 的一部分,我使用 Drag'n Drop Gridview 对此进行了测试。使用此解决方案拖动时,从左到右和从右到左拖动失败。我个人认为 Rajul 的方法是最好的。 在 Android 6 上(尚未在任何其他版本上测试过)如果您多次单击并向左拖动,您可以看到视图寻呼机向左滑动。这很有趣。【参考方案4】:

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_ 
    android:layout_ />

您只需要使用false 调用setPagingEnabled 方法,用户将无法滑动分页。

【讨论】:

完美适用于具有多个子视图的视图,其中一个使用水平滚动(例如 AChartEngine 图表)。在我的片段中,我对我的活动使用回调,告诉它根据用户是触摸(ACTION_MOVE)图表还是离开图表(ACTION_CANCEL)来关闭或关闭分页。非常感谢! 您可以使用return enabled &amp;&amp; super.onTouchEvent(event); 简化您的onTouchEventonInterceptTouchEvent 方法 我还建议将字段名称从“启用”更改为“swipePageChangeEnabled”或类似的名称。编写代码一个月后,您几乎不会记得“启用”是什么意思,尤其是当您的类称为“CustomViewPager”时,不清楚自定义是什么。这也是风格的问题,但如果你不想以不支持的项目结束,风格很重要,完全重写比修复它更容易。 在哪里调用 setPagingEnabled? ._. @Ntikki,你可以像这样声明你的ViewPager 之后调用setPagingEnabled() 方法:CustomViewPager yourCustomViewPager = (CustomViewPager) findViewById(R.id.yourCustomViewPager); yourCustomViewPager.setPagingEnabled(false)【参考方案5】:

最好将其声明为可样式化,以便您可以从 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_
    android:layout_
    app:swipeable="false" />

当然,您仍然可以拥有 get/set 属性。

【讨论】:

【参考方案6】:

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

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

【讨论】:

它一直等到下一页部分可见。将执行onPageSelected 中下一页的代码。甚至下一页也会切换。所以,这段代码不需要。【参考方案7】:

在特定页面(在本例中为第 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;

【讨论】:

【参考方案8】:

仅覆盖 onTouchEventonInterceptTouchEvent 是不够的,以防 ViewPager 本身位于另一个 ViewPager 中。子 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);
    


【讨论】:

谢谢,这在另一个 ViewPager 中的 ViewPager 上效果很好。 这适用于我,也适用于另一个 ViewPager 中的 ViewPager。在那种情况下,正确的解决方案对我不起作用。 在标签中使用时也会停止动画。 如果我禁用它并假设我想启用它,那么我可以在哪里获取调用 setSwipeLocked(false) 的事件?【参考方案9】:

禁用滑动

mViewPager.beginFakeDrag();

启用滑动

mViewPager.endFakeDrag();

【讨论】:

这不是一个好的解决方案,因为它允许小部分移动,至少在我的应用中是这样。【参考方案10】:

我用滑动控件写了一个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 中有一个按钮并且我想要点击怎么办?此解决方案会阻止单击 viewpager 下方的所有内容.. 我没有遇到@aimiliano 的问题。我的 ViewPager 中有多个可点击的项目,并且在这个解决方案中都可以正常工作。这对我来说非常有效!【参考方案11】:

我知道发布此内容为时已晚,但这里有一个小技巧可以实现您的结果;)

只需在您的浏览器下方添加一个虚拟视图:

<android.support.v4.view.ViewPager
     android:layout_
     android:layout_>
</android.support.v4.view.ViewPager>

<RelativeLayout
     android:id="@+id/dummyView"
     android:layout_
     android:layout_>
</RelativeLayout>

然后将OnClickListener 添加到您的RelativeLayout

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

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

在布局、布局和行为方面获得一点创意,您将学会找到一种方法来完成您想象的任何事情:)

祝你好运!

【讨论】:

如果您不需要处理onClick 事件,更简单的方法是使用setClickable 而不是setOnClickListener 这不会也阻止viewpager中的触摸吗? 会的。这是 OP @androiddeveloper 所需的预期行为 @RickGrimesTheCoder 我认为你没有理解我的问题。我的意思是viewpager片段中的视图。它们还能触摸吗? 不,他们不会,因为 viewpager 本身有一个点击监听器。这仅适用于片段中没有交互式元素的情况。例如一个 Welcome ViewPager 动态改变它的片段 @androiddeveloper【参考方案12】:

如果您从 ViewPager 扩展,您还必须覆盖 @araks 之前指出的 executeKeyEvent

@Override
public boolean executeKeyEvent(KeyEvent event)

    return isPagingEnabled ? super.executeKeyEvent(event) : false;

因为某些设备(例如 Galaxy Tab 4 10')会显示这些按钮,而大多数设备从不显示它们:

【讨论】:

三星总是为 Android 开发者搞砸事情。 @toobsco42 在这种情况下,三星并不孤单。 SwiftKey(流行的键盘应用程序)允许用户在键盘上放置箭头。 如果您想阻止某人使用键盘/跟踪球对您的寻呼机进行寻呼,这也是解决方法。【参考方案13】:

如果您想在 Xamarin 中为 Android 实现相同的功能,这里是 C# 的翻译

我选择将属性命名为“ScrollEnabled”。因为 ios 只是使用 excat 相同的命名。因此,您可以在两个平台上使用相同的命名,这对开发人员来说更容易。

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;
        
    

在 .axml 文件中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_>
  <YourNameSpace.ViewPackage.CustomViewPager
      android:id="@+id/pager"
      android:layout_
      android:layout_
      android:background="@android:color/white"
      android:layout_alignParentTop="true" />
</LinearLayout>

【讨论】:

【参考方案14】:

如果您使用支持缩放和平移的ImageViews 和ViewPager 编写图像库,请参阅此处描述的简单解决方案:Implementing a zoomable ImageView by Extending the Default ViewPager in Phimpme Android(和Github sample - 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;
        
    

【讨论】:

【参考方案15】:
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;
                                         
                                     );

【讨论】:

【参考方案16】:

以上代码都不能顺利运行。我试过了

<HorizontalScrollView
                    android:id="@+id/horizontalScrollView"
                    android:layout_
                    android:layout_
                    android:fillViewport="true">

                    <android.support.v4.view.ViewPager
                        android:id="@+id/pager"
                        android:layout_
                        android:layout_ />
                </HorizontalScrollView>

【讨论】:

【参考方案17】:

我成功地使用了这个类。需要覆盖 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_
    android:layout_ />

【讨论】:

它有效。只有滑动被禁用,并且单击选项卡被启用。 AS 警告performClick() 方法未被覆盖。【参考方案18】:

这是我的实现 如果你想禁用滑动动画,你可以左右使用 swipeListener 并且仍然希望通过手指滚动但没有动画

1-覆盖Viewpager方法onInterceptTouchEventonTouchEvent

2- 创建您自己的GestureDetector

3- 检测滑动手势并使用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();
    

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

            
             ...
           

【讨论】:

【参考方案19】:

我只是稍微定制了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);


【讨论】:

【参考方案20】:

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

一个新的ViewPager2名称视图在android中可用

Vertical orientation support

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

欲了解更多信息,请查看此

ViewPager2 ViewPager2 under the Hood Hands on With ViewPager2

更新

请查看:Migrate from ViewPager to ViewPager2

完整示例请查看Use of ViewPager2 in Android

【讨论】:

这很棒,但看起来仍然不完整。我已经用 5 个不同的片段进行了尝试,在页面之间切换后,其中一个片段有点丢失了,即视图既没有恢复也没有重新膨胀 我可以使用此方法成功禁用 ViewPager2 上的滑动 @voghDev 很高兴听到这个消息 @PhaniRithvij 请检查此答案***.com/a/54643817/7666442 我已添加所有详细信息如何使用viewpager2RecyclerView.Adapter 这应该被作为接受的答案。【参考方案21】:
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
            

        )

【讨论】:

【参考方案22】:

在我的解决方案 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
    

【讨论】:

覆盖onInterceptTouchEvent() 将阻止子视图接收输入。在大多数情况下,这不是预期的行为。 我能够与每个片段的子视图进行交互。不知道你指的是什么。【参考方案23】:

在 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_
    android:layout_
    android:layout_below="@id/tab_layout" />

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

view_pager.pagingEnabled = false

否则我们可以使用以下代码禁用刷卡:

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

【讨论】:

覆盖onInterceptTouchEvent() 将阻止子视图接收输入。在大多数情况下,这不是预期的行为。 @AlexSemeniuk 实施后您是否发现任何问题?我已经为某些操作启用了在回收站视图项目上滑动,它工作正常。因此,在我的情况下,实施工作正常。 Sagar Chapagain:当然,我做到了。我的每个页面都包含自定义视图,它以各种方式处理触摸(包括滚动、拖动、单击和长按)。不调用 super.onInterceptTouchEvent(event) 会导致这些视图没有收到任何输入(这是 onInterceptTouchEvent 方法的记录目的)。 如果是这种情况,您应该使用子片段并维护 backstack。 这与当前问题有什么关系?片段被放置在一些容器中(它们是 Views)并且它们自己的布局包含 Views。无论我在 ViewPager 中有什么内容,我仍然在处理这样一个事实,即覆盖 onInterceptTouchEvent() 方法会阻止它(内容)接收输入。【参考方案24】:

如果您使用的是 ViewPager2,您只需使用:

viewpager.setUserInputEnabled(false);

来自docs:

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

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

【讨论】:

【参考方案25】:

在科特林中

viewPagerNavigation.isUserInputEnabled = false

【讨论】:

【参考方案26】:
* 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*/)
        
    

【讨论】:

以上是关于如何通过在 ViewPager 中用手指滑动来禁用分页但仍然能够以编程方式滑动?的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用 ViewPager2 中的滑动?

禁用选项卡布局

如何在 iPhone 应用程序中用手指绘制虚线?

如何在 UIPageViewController 上禁用多点触控?

Android中ViewPager如何设置不能通过屏幕左右滑动来切换页面

通过在多个按钮上滑动手指来选择多个按钮