android viewpager滑動(dòng)卡頓
當(dāng)SwipeRefreshLayout中放置了ViewPager控件,兩者的滑動(dòng)會(huì)相互沖突.具體表現(xiàn)為ViewPager的左右滑動(dòng)不順暢,容易被SwipeRefreshLayout攔截(即出現(xiàn)刷新的View). 問(wèn)題原因:Vie
問(wèn)題說(shuō)明:當(dāng)SwipeRefreshLayout中放置了ViewPager控件,兩者的滑動(dòng)會(huì)相互沖突.具體表現(xiàn)為ViewPager的左右滑動(dòng)不順暢,容易被SwipeRefreshLayout攔截(即出現(xiàn)刷新的View).
問(wèn)題原因:ViewPager本身是處理了滾動(dòng)事件的沖突,它在橫向滑動(dòng)時(shí)會(huì)調(diào)用requestDisallowInterceptTouchEvent()方法使父控件不攔截當(dāng)前的Touch事件序列.但是SwipeRefreshLayout的requestDisallowInterceptTouchEvent()方法什么也沒(méi)有做,所以仍然會(huì)攔截當(dāng)前的Touch事件序列.
問(wèn)題分析:為什么SwipeRefreshLayout的requestDisallowInterceptTouchEvent()方法什么都不做?
首先SwipeRefreshLayout繼承自ViewGroup.
在requestDisallowInterceptTouchEvent()方法什么都不做的情況下,用戶(hù)可以從底部下拉刷新一次拉出LoadingView. 如果方法調(diào)用ViewGroup的requestDisallowInterceptTouchEvent()方法, 可以解決ViewPager的兼容問(wèn)題,但是用戶(hù)在界面底部下拉至頭部后,無(wú)法繼續(xù)下拉,需要手指放開(kāi)一次才能拉出LoadingView. 目標(biāo)分析: 那么為了更加順滑地滾動(dòng),想要的效果當(dāng)然是一次性拉出LoadingView.既然ViewPager在左右滑動(dòng)時(shí)才會(huì)調(diào)用requestDisallowInterceptTouchEvent()方法,那么SwipeRefreshLayout只應(yīng)該在上下滑動(dòng)時(shí)才攔截Touch事件.
具體邏輯如下:
記錄是否調(diào)用了requestDisallowInterceptTouchEvent()方法,并且設(shè)置為true. 在SwipeRefreshLayout中判斷是否是上下滑動(dòng). 如果同時(shí)滿(mǎn)足1,2,則調(diào)用super.requestDisallowInterceptTouchEvent(true). 否則調(diào)用super.requestDisallowInterceptTouchEvent(false). 注意:因?yàn)閂iewGroup的requestDisallowInterceptTouchEvent方法設(shè)置true后,Touch事件在dispatchTouchEvent()方法中就會(huì)被攔截,所以需要在dispatchTouchEvent()方法中判斷是否為上下滑動(dòng).
實(shí)現(xiàn)代碼(部分):
//非法按鍵
private static final int INVALID_POINTER = -1;
//dispatch方法記錄第一次按下的x
private float mInitialDisPatchDownX;
//dispatch方法記錄第一次按下的y
private float mInitialDisPatchDownY;
//dispatch方法記錄的手指
private int mActiveDispatchPointerId = INVALID_POINTER;
//是否請(qǐng)求攔截
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滑動(dòng)沖突問(wèn)題
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) {
//橫向滾動(dòng)不需要攔截
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);
}
大部分來(lái)自于:http://phpstudy.php.cn/b.php/103489.html