尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38942135

关于Android Touch事件传递机制我之前也写过两篇文章,自觉得对Touche事件还是理解得比較清楚的,可是近期遇到的一个问题,让我再次对Android Touche事件进行一次学习。

我的关于Android Touche事件传递机制的文章例如以下:

http://blog.csdn.net/yuanzeyao/article/details/37961997

http://blog.csdn.net/yuanzeyao/article/details/38025165

我在这两篇文章中得出过下面结论:

1、假设一个view是clickable的,那么这个View的onTouchEvent是一定会返回true的,也就是说不论什么触摸事件都会被消费掉

2、假设一个View对于ACTION_DOWN事件没有消费掉(onTouchEvent 返回false),那么兴许的ACTION_MOVE,ACTION_UP是都不会接受到的,也就是没有机会处理这些事件,这些事件都是在父View里面给处理了

3、假设一个ViewGroup想要拦截事件(不让事件传递到子View),那么它只须要改写ViewGroup的onInterceptTouchEvent(MotionEvent ev) 方法,让他返回true,或者调用requestDisallowInterceptTouchEvent(true);

4、Android中的Touche事件是从底层向上层传递的 Activity->DecorView->ViewGroup->View

理解了上面的问题,我们就開始看看我所遇到的问题吧,

在使用SlideMenu的时候,在中的Activity中只放置一个TextView,你会发现SlideMenu无法滑动,当时通过顶部的Title能够滑动,因为对SlideMenu用的不是非常熟,当时以为是SlideMenu的哪个属性用错了,后来一直没有解决这个问题,直到一位网友说设置TextView的clickable为true就能够解决这个问题,我尝试了一下,还真行!哈哈。。。,这个里面的原因你理解了吗?假设没有理解,请继续往下看

依照我之前对Touche事件的理解,假设设置clickable,那么Touche事件肯定就被TextView给消费掉了,假设被TextView消费掉了,那么SlideMenu怎样实现滑动?要解开这个问题答案,还是看看SlideMenu的源代码吗

我们首先看看SlideMenu中CustomViewAbove和Touche有关的方法

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { if (!mEnabled)
return false; final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; if (action == MotionEvent.ACTION_DOWN && DEBUG)
Log.v(TAG, "Received ACTION_DOWN"); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP
|| (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) {
endDrag();
return false;
} switch (action) {
case MotionEvent.ACTION_MOVE:
try{
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER)
break;
final int pointerIndex = this.getPointerIndex(ev, activePointerId);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float dx = x - mLastMotionX;
final float xDiff = Math.abs(dx);
final float y = MotionEventCompat.getY(ev, pointerIndex);
final float yDiff = Math.abs(y - mLastMotionY);
if (DEBUG) Log.v(TAG, "onInterceptTouch moved to:(" + x + ", " + y + "), diff:(" + xDiff + ", " + yDiff + "), mLastMotionX:" + mLastMotionX);
if (xDiff > mTouchSlop && xDiff > yDiff && thisSlideAllowed(dx)) {
if (DEBUG) Log.v(TAG, "Starting drag! from onInterceptTouch");
startDrag();
mLastMotionX = x;
setScrollingCacheEnabled(true);
} else if (yDiff > mTouchSlop) {
mIsUnableToDrag = true;
}
}
catch(IllegalArgumentException e)
{
e.printStackTrace();
}
break; case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getAction() & ((Build.VERSION.SDK_INT >= 8) ? MotionEvent.ACTION_POINTER_INDEX_MASK :
MotionEvent.ACTION_POINTER_INDEX_MASK);
mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, mActivePointerId);
mLastMotionY = MotionEventCompat.getY(ev, mActivePointerId);
if (thisTouchAllowed(ev)) {
mIsBeingDragged = false;
mIsUnableToDrag = false;
if (isMenuOpen() && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {
mQuickReturn = true;
}
} else {
mIsUnableToDrag = true;
}
break;
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
} if (!mIsBeingDragged) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
}
return mIsBeingDragged || mQuickReturn;
}

看看这种方法,这种方法里面有个逻辑就是当滑动到一定距离,就会返回true,也就是说会拦截滑动事件,第一个ACTION_DOWN肯定不会拦截。

再看看onToucheEvent.java

	@Override
public boolean onTouchEvent(MotionEvent ev) { if (!mEnabled)
return false; // if (!mIsBeingDragged && !thisTouchAllowed(ev))
// return false; if (!mIsBeingDragged && !mQuickReturn)
return false; final int action = ev.getAction(); if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev); switch (action & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
completeScroll(); // Remember where the motion event started
mLastMotionX = mInitialMotionX = ev.getX();
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
break;
case MotionEvent.ACTION_MOVE:
if (!mIsBeingDragged) {
if (mActivePointerId == INVALID_POINTER)
break;
final int pointerIndex = getPointerIndex(ev, mActivePointerId);
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float dx = x - mLastMotionX;
final float xDiff = Math.abs(dx);
final float y = MotionEventCompat.getY(ev, pointerIndex);
final float yDiff = Math.abs(y - mLastMotionY);
if (DEBUG) Log.v(TAG, "onTouch moved to:(" + x + ", " + y + "), diff:(" + xDiff + ", " + yDiff + ")\nmIsBeingDragged:" + mIsBeingDragged + ", mLastMotionX:" + mLastMotionX);
if ((xDiff > mTouchSlop || (mQuickReturn && xDiff > mTouchSlop / 4))
&& xDiff > yDiff && thisSlideAllowed(dx)) {
if (DEBUG) Log.v(TAG, "Starting drag! from onTouch");
startDrag();
mLastMotionX = x;
setScrollingCacheEnabled(true);
} else {
if (DEBUG) Log.v(TAG, "onTouch returning false");
return false;
}
}
if (mIsBeingDragged) {
// Scroll to follow the motion event
final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
if (mActivePointerId == INVALID_POINTER) {
break;
}
final float x = MotionEventCompat.getX(ev, activePointerIndex);
final float deltaX = mLastMotionX - x;
mLastMotionX = x;
float oldScrollX = getScrollX();
float scrollX = oldScrollX + deltaX;
final float leftBound = getLeftBound();
final float rightBound = getRightBound();
if (scrollX < leftBound) {
scrollX = leftBound;
} else if (scrollX > rightBound) {
scrollX = rightBound;
}
// Don't lose the rounded component
mLastMotionX += scrollX - (int) scrollX;
scrollTo((int) scrollX, getScrollY());
pageScrolled((int) scrollX);
}
break;
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
velocityTracker, mActivePointerId);
final int scrollX = getScrollX();
// final int widthWithMargin = getWidth();
// final float pageOffset = (float) (scrollX % widthWithMargin) / widthWithMargin;
// TODO test this. should get better flinging behavior
final float pageOffset = (float) (scrollX - getDestScrollX(mCurItem)) / getBehindWidth();
final int activePointerIndex = getPointerIndex(ev, mActivePointerId);
if (mActivePointerId != INVALID_POINTER) {
final float x = MotionEventCompat.getX(ev, activePointerIndex);
final int totalDelta = (int) (x - mInitialMotionX);
int nextPage = determineTargetPage(pageOffset, initialVelocity, totalDelta);
setCurrentItemInternal(nextPage, true, true, initialVelocity);
} else {
setCurrentItemInternal(mCurItem, true, true, initialVelocity);
}
mActivePointerId = INVALID_POINTER;
endDrag();
} else if (mQuickReturn && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {
// close the menu
setCurrentItem(1);
endDrag();
}
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged) {
setCurrentItemInternal(mCurItem, true, true);
mActivePointerId = INVALID_POINTER;
endDrag();
}
break;
case MotionEventCompat.ACTION_POINTER_DOWN: {
final int index = MotionEventCompat.getActionIndex(ev);
final float x = MotionEventCompat.getX(ev, index);
mLastMotionX = x;
mActivePointerId = MotionEventCompat.getPointerId(ev, index);
break;
}
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
int pointerIndex = this.getPointerIndex(ev, mActivePointerId);
if (mActivePointerId == INVALID_POINTER)
break;
mLastMotionX = MotionEventCompat.getX(ev, pointerIndex);
break;
}
return true;
}

我们重点观察ACTION_DWON事件,对于ACTION_DWON事件,SlideMenu是没有拦截的,所以传递到了TextView,因为默认TextView是没有clickable的,所以是不会消费这个事件,假设TextView不消费,那么事件就传递到了SlideMenu,可是我们发如今SlideMenu中也没有消费这个事件,还记得我们上面的结论2吗,依据结论2,我们知道后面的事件是传递只是来的,所以导致了SlideMenu无法滑动。

假设我们设置了clickable,那么第一个ACTION_DOWN就被TextView处理了,所以后面每一个事件都会传递到TextView(前提是不被拦截,实际结果是被拦截,并被SlideMenu处理,所以SlideMenu滑动了)

Android Touch事件传递机制引发的血案的更多相关文章

  1. Android Touch事件传递机制 二:单纯的(伪生命周期)

    转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...

  2. Android Touch事件传递机制 一: OnTouch,OnItemClick(监听器),dispatchTouchEvent(伪生命周期)

      ViewGroup View  Activity dispatchTouchEvent 有 有 有 onInterceptTouchEvent 有 无 无 onTouchEvent 有 有 有 例 ...

  3. Android touch 事件传递机制

    前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事 ...

  4. Android Touch事件传递机制通俗讲解

    在讲正题之前我们讲一段有关任务传递的小故事,抛砖迎玉下: 话说一家软件公司,来一个任务,分派给了开发经理去完成: 开发经理拿到,看了一下,感觉好简单,于是 开发经理:分派给了开发组长 开发组长:分派给 ...

  5. Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点

    转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...

  6. Android Touch事件传递机制详解 下

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...

  7. Android Touch事件传递机制具体解释 下

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...

  8. (转)Android Touch事件传递机制

    -----来源:http://www.trinea.cn/android/touch-event-delivery-mechanism/ 介绍Android Touch事件的传递机制. 不少朋友私信问 ...

  9. Android Touch事件传递机制具体解释 上

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/37961997 近期总是遇到关于Android Touch事件的问题,如:滑动冲突的问题,曾经 ...

随机推荐

  1. 树形dp入门(poj 2342 Anniversary party)

    题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知每个人的活跃指数和上司关系(当然不可能存在环),求邀请哪些人(多少人)来能使得晚 ...

  2. luogu P1353 [USACO08JAN]跑步Running

    题目描述 The cows are trying to become better athletes, so Bessie is running on a track for exactly N (1 ...

  3. [BZOJ 2427] 软件安装

    Link: BZOJ 2427 传送门 Solution: 只看样例的话会以为是裸的树形$dp$…… 但实际上题目并没有说明恰好仅有一个物品没有依赖项 因此原图可能由是由多棵树与多个图组成的 先跑一遍 ...

  4. 「PKUSC2018」星际穿越 (70分做法)

    5371: [Pkusc2018]星际穿越 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 27  Solved: 11[Submit][Status] ...

  5. 【hdu1280】前M大的数

    前m大的数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  6. 【动态规划】POJ3280- Cheapest Palindrome

    [题目大意] 给出一个字符串,可以删除或添加一些字符,它们各自会消耗价值.问最少消耗多少价值,可以使得字符串变成回文的. [思路] 事实上删除或添加字符的价值只需要保持较小的那一个.假设当前要将(j, ...

  7. SourceTree运行慢的解决方案

    以下两个Git命令可以解决SourceTree运行慢: git gc git prune 可以在SourceTree点击命令行模式打开Git命令行窗口输入,等待片刻执行完成,SourceTree的运行 ...

  8. Java学习笔记(7)

    构造函数: 构造函数的作用:给对应的对象进行初始化. 构造函数定义的格式: 修饰符   函数名(形式参数){ 函数体... } 构造函数要注意的细节: 构造函数是没有返回值类型的 构造函数的函数名必须 ...

  9. [HTML/CSS]div显示在object、embed之上~

    引言 帮一个朋友弄前端布局,一切都正常,但是嵌入object之后,div总是在object的下面,就上网找了一下解决方案,这里记录一下,好像只对flash有效. 用embed插入一个flash(比如优 ...

  10. 解决新浪微博API调用限制 突破rate_limit_status瓶颈

    新浪微博开放平台API的调用和TWITTER接口一样,都是受限的,以小时为单位进行限定. 他有两个限制原则 1.用户不登录基于IP的限制,每小时1000次 2.用户登录了基于用户的限制,每小时1000 ...