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如下: 文章图片
当”setCurrentItem(1,true)”或者手指向左滑动手指从按下到离开中间所经历的Log
文章图片
分析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);
}
}
推荐阅读
- parallels|parallels desktop 解决网络初始化失败问题
- android第三方框架(五)ButterKnife
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- Android中的AES加密-下
- 带有Hilt的Android上的依赖注入
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- android|android studio中ndk的使用
- Android事件传递源码分析