Android 解决 ViewPager OnTouchListener 方法监听无效

解决 ViewPager OnTouchListener 方法监听无效 工作中在做首页轮播图时有一个需求, 当用户滑动轮播图时暂停自动轮播, 用户手指离开屏幕时重新开始自动轮播. 此时我想到了使用setOnTouchListener 方法设置一个监听在用户ACTION_DWON和ACTION_UP时, 停止和开始自动轮播, 但跑起来后发现onTouch方法压根没有执行. 测试后发现, 如果onTouch方法返回值return false, 则监听收不到事件, 如果onTouch方法返回true, 则ViewPager不能正常滑动.
然后我突然想到addOnPageChangeListener方法,其中的onPageScrolled回调在viewPager滑动时可以通过参数positionOffset实时监听滑动距离:

addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { Log.i("DEFAULT","position:"+position+" positionOffset:"+positionOffset+" positionOffsetPixels:"+positionOffsetPixels); } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } });

突发奇想打印Log看看:
setCurrentItem(1,false)执行时打印Log如下:
Android 解决 ViewPager OnTouchListener 方法监听无效
文章图片

当”setCurrentItem(1,true)”或者手指向左滑动手指从按下到离开中间所经历的Log
Android 解决 ViewPager OnTouchListener 方法监听无效
文章图片

分析Log后, 发现在不考虑 setCurrentItem 方法执行的情况下, 当positionOffset为0时永远代表ACTION_UP事件, 当positionOffset不为0时, 除第一次非零数据是ACTION_DOWN事件外, 其余都是ACTION_MOVE事件, 当然拿不到点击位置, 这也是没有办法的事.
于是我想到了继承ViewPager, 通过该监听事件, 模拟出onTouchListener监听.
【Android 解决 ViewPager OnTouchListener 方法监听无效】具体代码如下, 定义三个状态 up move down, 默认状态是up, 通过监听onPageScrolled方法, positionOffset 为0时改变状态为up, 非0时如果状态为up则改变为down, 如果状态为down则改变状态为move, 设置开关setCurrentItemNoAnimStart来防止setCurrentItem(1,false|true)导致误触发事件, 虽然最终结果接收到down 和 up事件时有迟缓并且得不到按下位置, 但能够得到 down up move 三种状态已经完美解决了轮播图的需求.
希望这篇博文也能帮到正在看的你.
补充: 最近看了一些博客, 找到一种更好的方案解决 ViewPager监听问题, 做法是重写 viewPager dispatchTouchEvent 方法, 在该方法里写一个监听事件, 简单高效, 能更快更准确的获取到监听, 不得不承认比我的方法好.
// 大神的方案... public class SuperViewPager extends ViewPager{ public static final int STATE_DOWN = MotionEvent.ACTION_DOWN; public static final int STATE_UP = MotionEvent.ACTION_UP; public static final int STATE_MOVE = MotionEvent.ACTION_MOVE; int state = STATE_UP; public SuperViewPager(Context context) { super(context); public SuperViewPager(Context context, AttributeSet attrs) { super(context, attrs); }@Override public boolean dispatchTouchEvent(MotionEvent ev) { if(mOnTouchListener != null) mOnTouchListener.onTouch(ev.getAction()); return super.dispatchTouchEvent(ev); }public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l; }OnTouchListener mOnTouchListener; interface OnTouchListener { void onTouch(int state); } }

// 我的方案 public class SuperViewPager extends ViewPager{ public static final int STATE_DOWN = 0; public static final int STATE_UP = 1; public static final int STATE_MOVE = -1; int state = STATE_UP; boolean setCurrentItemNoAnimStart; private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { //Log.i(Util.getTag(null),"position:"+position+" positionOffset:"+positionOffset+" positionOffsetPixels:"+positionOffsetPixels); //... 相当于 viewpager onTouchListener if(positionOffset == 0){ //Log.i(Util.getTag(null),"HAHA_position:"+position); if(setCurrentItemNoAnimStart){ setCurrentItemNoAnimStart = false; }else { state = STATE_UP; if (mOnTouchListener != null) mOnTouchListener.onTouch(STATE_UP); } }else{ if(!setCurrentItemNoAnimStart){ if (state == STATE_UP) { state = STATE_DOWN; if (mOnTouchListener != null) mOnTouchListener.onTouch(STATE_DOWN); } else if(state == STATE_DOWN) { state = STATE_MOVE; if (mOnTouchListener != null) mOnTouchListener.onTouch(STATE_MOVE); } } } //... }@Override public void onPageSelected(int position) { }@Override public void onPageScrollStateChanged(int state) { } }; public SuperViewPager(Context context) { super(context); }public SuperViewPager(Context context, AttributeSet attrs) { super(context, attrs); addOnPageChangeListener(mOnPageChangeListener); }@Override public void setCurrentItem(int item, boolean smoothScroll) { if(!smoothScroll) setCurrentItemNoAnimStart = true; super.setCurrentItem(item, smoothScroll); }public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l; } OnTouchListener mOnTouchListener; interface OnTouchListener { void onTouch(int state); } }

    推荐阅读