问题说明:
当SwipeRefreshLayout中放置了ViewPager控件,两者的滑动会相互冲突.具体表现为ViewPager的左右滑动不顺畅,容易被SwipeRefreshLayout拦截(即出现刷新的View).
问题原因:
ViewPager本身是处理了滚动事件的冲突,它在横向滑动时会调用requestDisallowInterceptTouchEvent()方法使父控件不拦截当前的Touch事件序列.但是SwipeRefreshLayout的requestDisallowInterceptTouchEvent()方法什么也没有做,所以仍然会拦截当前的Touch事件序列.
问题分析:
为什么SwipeRefreshLayout的requestDisallowInterceptTouchEvent()方法什么都不做?
首先SwipeRefreshLayout继承自ViewGroup.
在requestDisallowInterceptTouchEvent()方法什么都不做的情况下,用户可以从底部下拉刷新一次拉出LoadingView.
如果方法调用ViewGroup的requestDisallowInterceptTouchEvent()方法, 可以解决ViewPager的兼容问题,但是用户在界面底部下拉至头部后,无法继续下拉,需要手指放开一次才能拉出LoadingView.
目标分析:
那么为了更加顺滑地滚动,想要的效果当然是一次性拉出LoadingView.既然ViewPager在左右滑动时才会调用requestDisallowInterceptTouchEvent()方法,那么SwipeRefreshLayout只应该在上下滑动时才拦截Touch事件.
具体逻辑如下:
记录是否调用了requestDisallowInterceptTouchEvent()方法,并且设置为true.
在SwipeRefreshLayout中判断是否是上下滑动.
如果同时满足1,2,则调用super.requestDisallowInterceptTouchEvent(true).
否则调用super.requestDisallowInterceptTouchEvent(false).
注意:因为ViewGroup的requestDisallowInterceptTouchEvent方法设置true后,Touch事件在dispatchTouchEvent()方法中就会被拦截,所以需要在dispatchTouchEvent()方法中判断是否为上下滑动.
实现代码(部分):
//非法按键
private static final int INVALID_POINTER = -1;
//dispatch方法记录第一次按下的x
private float mInitialDisPatchDownX;
//dispatch方法记录第一次按下的y
private float mInitialDisPatchDownY;
//dispatch方法记录的手指
private int mActiveDispatchPointerId = INVALID_POINTER;
//是否请求拦截
private boolean hasRequestDisallowIntercept = false;
@Override
public void requestDisallowInterceptTouchEvent(boolean b) {
hasRequestDisallowIntercept = b;
// Nope.
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mActiveDispatchPointerId = MotionEventCompat.getPointerId(ev, 0);
final float initialDownX = getMotionEventX(ev, mActiveDispatchPointerId);
if (initialDownX != INVALID_POINTER) {
mInitialDisPatchDownX = initialDownX;
}
final float initialDownY = getMotionEventY(ev, mActiveDispatchPointerId);
if (mInitialDisPatchDownY != INVALID_POINTER) {
mInitialDisPatchDownY = initialDownY;
}
break;
case MotionEvent.ACTION_MOVE:
if (hasRequestDisallowIntercept) {
//解决viewPager滑动冲突问题
final float x = getMotionEventX(ev, mActiveDispatchPointerId);
final float y = getMotionEventY(ev, mActiveDispatchPointerId);
if (mInitialDisPatchDownX != INVALID_POINTER && x != INVALID_POINTER &&
mInitialDisPatchDownY != INVALID_POINTER && y != INVALID_POINTER) {
final float xDiff = Math.abs(x - mInitialDisPatchDownX);
final float yDiff = Math.abs(y - mInitialDisPatchDownY);
if (xDiff > mTouchSlop && xDiff * 0.7f > yDiff) {
//横向滚动不需要拦截
super.requestDisallowInterceptTouchEvent(true);
} else {
super.requestDisallowInterceptTouchEvent(false);
}
} else {
super.requestDisallowInterceptTouchEvent(false);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) {
hasRequestDisallowIntercept = false;
}
break;
}
return super.dispatchTouchEvent(ev);
}
private float getMotionEventY(MotionEvent ev, int activePointerId) {
final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
if (index < 0) {
return -1;
}
return MotionEventCompat.getY(ev, index);
}
private float getMotionEventX(MotionEvent ev, int activePointerId) {
final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
if (index < 0) {
return -1;
}
return MotionEventCompat.getX(ev, index);
}
您可能感兴趣的文章:Android利用ViewPager实现滑动广告板实例源码Android App中ViewPager所带来的滑动冲突问题解决方法Android App中使用ViewPager+Fragment实现滑动切换效果Android开发之使用ViewPager实现图片左右滑动切换效果Android ViewPager无限循环实现底部小圆点动态滑动android配合viewpager实现可滑动的标签栏示例分享Android利用ViewPager实现可滑动放大缩小画廊效果android viewpager实现竖屏滑动效果Android自定义ViewPager实现纵向滑动翻页效果android viewpager实现竖直滑动效果