此篇文章使用外部攔截法解決View內(nèi)外滑動方向不一致的沖突問題
1. 問題描述
外部用HorizontalScrollViewEx模擬ViewPager相艇,內(nèi)部用ListView。上下滑動則ListView滾動,左右滑動則HorizontalScrollView滾動往果。下面這篇文章已經(jīng)實(shí)現(xiàn)了HorizontalScrollView急黎,這里只解決滑動沖突問題。
4.4 View的示例(二)
2. HorizontalScrollViewEx中攔截事件
public class HorizontalScrollViewEx extends ViewGroup {
private int mChildrenSize;
private int mChildWidth;
private int mChildIndex;
private int mLastX;
private int mLastY;
private int mLastInterceptX = 0;
private int mLastInterceptY = 0;
private Scroller mscroller;
private VelocityTracker mVelocityTracker;
public HorizontalScrollViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
mscroller = new Scroller(getContext());
mVelocityTracker = VelocityTracker.obtain();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 這里必須返回false缩幸,因?yàn)檫@里如果父View攔截了髓堪,子View收不到后續(xù)事件,應(yīng)該讓子View拿到Down事件搞坝,父View攔截Move事件搔谴。
intercepted = false;
if (!mscroller.isFinished()) {
// 沒結(jié)束,強(qiáng)制結(jié)束
mscroller.abortAnimation();
intercepted = true;
}
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastInterceptX;
int deltaY = y - mLastInterceptY;
// 這里根據(jù)條件判斷是否需要攔截
if (Math.abs(deltaX) > Math.abs(deltaY)) {
intercepted = true;
} else {
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
// 這里返回false桩撮,因?yàn)閡p沒什么意義了
intercepted = false;
break;
case MotionEvent.ACTION_CANCEL:
break;
}
mLastX = x;
mLastY = y;
mLastInterceptX = x;
mLastInterceptY = y;
return intercepted;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mVelocityTracker.addMovement(event);
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!mscroller.isFinished()) {
// 沒結(jié)束敦第,強(qiáng)制結(jié)束
mscroller.abortAnimation();
}
break;
case MotionEvent.ACTION_MOVE:
// move的時候,調(diào)用scrollBy跟著滾動就可以
int deltaX = x - mLastX;
scrollBy(-deltaX, 0);
break;
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
mVelocityTracker.computeCurrentVelocity(1000);
float xVelocity = mVelocityTracker.getXVelocity();
Log.e("aaa","xVelocity="+xVelocity);
if (Math.abs(xVelocity) >= 50) {
// 有速度則根據(jù)速度判斷上一頁或下一頁
// 速度為正店量,則向右正向芜果,左一頁
mChildIndex = xVelocity > 0 ? mChildIndex - 1 : mChildIndex + 1;
} else {
// 沒有速度則根據(jù)位置判斷上一頁或下一頁
mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth;
}
mChildIndex = Math.max(0, Math.min(mChildIndex, mChildrenSize - 1));
int dx = mChildIndex * mChildWidth - scrollX;
// 使用scroller滾動
smoothScrollBy(dx, 0);
mVelocityTracker.clear();
break;
case MotionEvent.ACTION_CANCEL:
break;
}
mLastX = x;
mLastY = y;
return super.onTouchEvent(event);
}
private void smoothScrollBy(int dx, int dy) {
mscroller.startScroll(getScrollX(), 0, dx, 0, 500);
invalidate();
}
@Override
public void computeScroll() {
super.computeScroll();
if (mscroller.computeScrollOffset()) {
scrollTo(mscroller.getCurrX(), mscroller.getCurrY());
postInvalidate();
}
}
@Override
protected void onDetachedFromWindow() {
// 做回收工作
mVelocityTracker.recycle();
super.onDetachedFromWindow();
}
}