?因為我在項目中遇到了這樣一個問題:我的主頁面是一個scrollview,里面包含了一個橫向顯示圖片的listview,在滑動橫向listview的時候scrollview也在微微上下滑動,此時的橫向listview滑動起來也是出現非常卡頓的情況。因此我百度看了很多資料,很多都講了一大篇的理論,看得頭暈眼花。我后來總結了一下,實際怎么解決這樣的問題;
首先,每個listview或則scrollview的源代碼中有這么一段代碼,如下:
~~~
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
/*
* This method JUST determines whether we want to intercept the motion.
* If we return true, onMotionEvent will be called and we do the actual
* scrolling there.
*/
/*
* Shortcut the most recurring case: the user is in the dragging
* state and he is moving his finger. We want to intercept this
* motion.
*/
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
return true;
}
/*
* Don't try to intercept touch if we can't scroll anyway.
*/
if (getScrollY() == 0 && !canScrollVertically(1)) {
return false;
}
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
/*
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
* whether the user has moved far enough from his original down touch.
*/
/*
* Locally do absolute value. mLastMotionY is set to the y value
* of the down event.
*/
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER) {
// If we don't have a valid id, the touch down wasn't on content.
break;
}
final int pointerIndex = ev.findPointerIndex(activePointerId);
if (pointerIndex == -1) {
Log.e(TAG, "Invalid pointerId=" + activePointerId
+ " in onInterceptTouchEvent");
break;
}
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop) {
mIsBeingDragged = true;
mLastMotionY = y;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
if (mScrollStrictSpan == null) {
mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
}
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
final int y = (int) ev.getY();
if (!inChild((int) ev.getX(), (int) y)) {
mIsBeingDragged = false;
recycleVelocityTracker();
break;
}
/*
* Remember location of down touch.
* ACTION_DOWN always refers to pointer index 0.
*/
mLastMotionY = y;
mActivePointerId = ev.getPointerId(0);
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
/*
* If being flinged and user touches the screen, initiate drag;
* otherwise don't. mScroller.isFinished should be false when
* being flinged.
*/
mIsBeingDragged = !mScroller.isFinished();
if (mIsBeingDragged && mScrollStrictSpan == null) {
mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
recycleVelocityTracker();
if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
postInvalidateOnAnimation();
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
/*
* The only time we want to intercept motion events is if we are in the
* drag mode.
*/
return mIsBeingDragged;
}
~~~
其實大家只要知道這個方法是事件攔截就行了,關于他的具體機制去看看這篇博客[點擊打開鏈接](http://blog.csdn.net/chunqiuwei/article/details/41084921),寫得很詳細,好了我們接下來就要在我們的自定義組件中覆寫這個方法就行了,一切就是這么簡單。我實現的是在scrollview中嵌套一個橫向滑動的ListView,先來看看我復寫的ScrollView:
~~~
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class MyScrollView extends ScrollView {
private float mDX, mDY, mLX, mLY;
int mLastAct = -1;
boolean mIntercept = false;
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyScrollView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN :
mDX = mDY = 0f;
mLX = ev.getX();
mLY = ev.getY();
break;
case MotionEvent.ACTION_MOVE :
final float curX = ev.getX();
final float curY = ev.getY();
mDX += Math.abs(curX - mLX);
mDY += Math.abs(curY - mLY);
mLX = curX;
mLY = curY;
if (mIntercept && mLastAct == MotionEvent.ACTION_MOVE) {
return false;
}
if (mDX > mDY) {
mIntercept = true;
mLastAct = MotionEvent.ACTION_MOVE;
return false;
}
}
mLastAct = ev.getAction();
mIntercept = false;
return super.onInterceptTouchEvent(ev);}
~~~
好了,接下來我為大家詳細講解這個方法的具體含義;首先,這方法是View的事件攔截,如果返回true的話,說明觸摸事件(包括DOWN,MOVE,UP)不會往下面傳遞,就在該view上面處理了,怎么理解呢?例如我的ScrollView是A ,橫向的ListView是B,?? B包含在A中,B是A的子view。那么觸摸事件是先讓A判斷了,然后再傳給B。如果在A中實現上面那個事件攔截事件,在特定情況下才將事件傳給B處理,如果不是B的事件,那個A就不會傳給B,這樣A和B就分離開了。
其中
~~~
if (mDX > mDY)
?{
mIntercept = true;
mLastAct = MotionEvent.ACTION_MOVE;
return false;
}
~~~
就是判斷 手指在屏幕上面滑動的 方向,這里判斷出是在橫向上面滑動,那么就返回false,表示不攔截這個事件,這個事件就會傳到B,讓B來處理這個事件,剛好B是橫向的Listview,就會對橫向方向的滑動事件進行處理。如果手指滑動的方向不是橫向,就supper父類的默認攔截事件。這里就相當于給攔截事件增加了一些判斷,而增加的判斷無非就是手指的滑動方向,ListView或ScrollView都是豎向的,而橫向的ListView和橫向滑動的Veiwpager是橫向的,不管是誰嵌套誰,只需要在重寫第一個View,把它的
~~~
public boolean onInterceptTouchEvent(MotionEvent ev)
~~~
方法重新寫一下,就可以解決手勢沖突的問題!
希望對大家的學習和工作有所幫助,謝謝!
- 前言
- viewpager
- 實現橫向listview(HorizontalListview)
- SimpleAdapter的使用
- 自定義android圓形ImageView
- 如何解決listView或scrollView+viewpager手勢沖突的問題
- EditText怎樣設置成下劃線
- Android中Display及DisplayMetrics理解
- android開發小經驗總結
- listView動態影藏顯現列表項中的多項部分
- Android開發中怎樣使用cookieManager來管理cookie
- 學習Android從0開始之背景篇-Android系統介紹
- 學習Android從0開始之開發工具篇-Android studio詳解
- 學習Android從0開始之基礎篇(1)-Android的四大基本組件
- 學習Android從0開始之基礎篇(2)-AndroidMainfest.xml文件詳解
- 學習Android從0開始之基礎篇(3)-視圖組件之布局管理器
- 學習Android從0開始之基礎篇(4)-TextView與EditText