Android Touch事件传递机制引发的血案

时间:2021-03-04 08:56:39

尊重原创: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. TIJ——Chapter Eight&colon;Polymorphism

    The twist |_Method-call binding Connecting a method call to a method body is called binding. When bi ...

  2. Jquery 下实现 图片大图预览效果

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  3. 【node&period;js】安装express后,&&num;39&semi;express&&num;39&semi; 不是内部或外部命令的问题

    因express默认安装是最新的版本,已经是4.x.x的版本.而最新express4.0+版本中将命令工具分出来了,所以必须要安装express-generator,执行: D:\TOOLS\Node ...

  4. oracle学习总结

    set linesize 120 set pagesize 20 column file_name format a8 v$nls_parameters 数据字典中的一个表 关于null的注意: 1: ...

  5. CSS3——复杂选择器

    今天把视频里的CSS3复杂选择器部分看完了,来整理一下学到的知识点. 1.兄弟选择器:同一位置级别,可称为兄弟元素 a.相邻兄弟选择器:next紧紧跟在[当前元素之后的](一个),指定选择器的元素   ...

  6. 201521123114 《Java程序设计》第10周学习总结

    1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 1. 创建线程方式: 定义Thread的子类 定义实现Runnable接口的类,实现run() 2. 调用s ...

  7. Node&period;js Web 模块

    什么是 Web 服务器? Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务.它只需支持HTTP协议.HTML文档格式及URL,与客 ...

  8. 浅谈百度地图API的坑

    我们可以使用百度地图生成器生成地图码(功能开发 还是使用官方文档吧) 注意百度地图坑 1.地图和我们申请的ak码版本问题 (解决方案:推荐大家使用2.0) 远程链接:<script type=& ...

  9. Android学习笔记(五一):服务Service(上)- IntentService

    转自 http://blog.csdn.net/flowingflying/article/details/7616333 对于需要长期运行,例如播放音乐.长期和服务器的连接,即使已不是屏幕当前的ac ...

  10. C语言 for循环之阶乘的算法

    int n; scanf("%d", &n); int fact = 1; int i = 1; while ( i <= n ) { fact *=i; i++; ...