首页 文章

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

提问于
浏览
442

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

17 回答

  • 92

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

    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);
                }
            }
    
  • 26
    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;
                                             }
                                         });
    
  • 11

    如果在另一个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);
        }
    
    }
    
  • 24

    如果你想在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://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>
    
  • 416

    以上代码都没有顺利运行 . 我试过这个

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

    您需要继承ViewPager . 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.
         */
    

    这是一个完整的解决方案:

    首先,将此类添加到您的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(); 方法用于平滑过渡

  • 0

    我知道发布这篇文章的时间太晚了,但这是一个很小的黑客来实现你的结果;)

    只需添加一个虚拟视图 below 您的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
        }
    });
    

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

    祝好运!

  • 4

    最好声明它是可设置的,因此您可以从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属性 .

  • 51

    我用一个滑动控件写了 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 则相反 .

    我在我的项目中使用它,直到现在它都运行良好 .

  • 1

    我成功地使用了这门课程 . 需要覆盖 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" />
    
  • 794

    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 方法,用户将无法滑动到分页 .

  • 44

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

  • 0

    要禁用滑动

    mViewPager.beginFakeDrag();
    

    启用滑动

    mViewPager.endFakeDrag();
    
  • 1

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

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

    如果您从ViewPager扩展, you must also override executeKeyEvent ,如@araks先前所示

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

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

  • 14

    这里描述了一个简单的解决方案:Implementing a zoomable ImageView by Extending the Default ViewPager in Phimpme Android(和Github sample - 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;
            }
        }
    }
    
  • 0

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

相关问题