Android事件分发
来源:互联网 发布:工业造型设计书籍知乎 编辑:程序博客网 时间:2024/06/06 14:00
郭霖的专栏:http://blog.csdn.net/guolin_blog/article/details/9097463
Carson_Ho的博客:http://blog.csdn.net/carson_ho/article/details/54136311
事件分发
1.基础知识
1.1事件分发的对象
- 答:事件
- 任何事件列都是以DOWN事件开始,UP事件结束,中间有无数的MOVE事件
- 事件列:手指从接触屏幕到离开屏幕,产生的一些列事件
1.2事件分发的本质
- 将点击时间像某个View进行传递并最终得到处理
- 传递的过程就是分发过程
1.3事件在哪些对象之间进行传递?
- 答:Activity、ViewGroup、View
- 一个点击事件产生后,传递顺序是:Activity(Window) -> ViewGroup -> View
1.4事件分发过程由哪些方法协作完成?
- 答:dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()
1.5总结
分发机制本质要解决:点击事件由哪个对象发出,经过哪些对象,最终达到哪个对象并最终得到处理。
源码解析
View
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event); }
该方法首先是进入一个if判断块,判断的第一个条件mOnTouchListener赋值的地方是在:
public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l; }
即当我们给控件注册了OnTouchListener时,该变量就不为null.
第二个条件(mViewFlags & ENABLED_MASK) == ENABLED
是判断控件是否enable
第三个条件mOnTouchListener.onTouch(this, event)
是如果注册了Touch事件,就会去回调该函数,如果onTouch()方法返回值为true,直接在dispatchTouchEvent()返回true;否则往下执行该控件的onTouchEvent()方法:
public boolean onTouchEvent(MotionEvent event) { final int viewFlags = mViewFlags; if ((viewFlags & ENABLED_MASK) == DISABLED) { // A disabled view that is clickable still consumes the touch // events, it just doesn't respond to them. return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); } if (mTouchDelegate != null) { if (mTouchDelegate.onTouchEvent(event)) { return true; } } if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { switch (event.getAction()) { case MotionEvent.ACTION_UP: boolean prepressed = (mPrivateFlags & PREPRESSED) != 0; if ((mPrivateFlags & PRESSED) != 0 || prepressed) { // take focus if we don't have it already and we should in // touch mode. boolean focusTaken = false; if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { focusTaken = requestFocus(); } if (!mHasPerformedLongPress) { // This is a tap, so remove the longpress check removeLongPressCallback(); // Only perform take click actions if we were in the pressed state if (!focusTaken) { // Use a Runnable and post this rather than calling // performClick directly. This lets other visual state // of the view update before click actions start. if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); } } } if (mUnsetPressedState == null) { mUnsetPressedState = new UnsetPressedState(); } if (prepressed) { mPrivateFlags |= PRESSED; refreshDrawableState(); postDelayed(mUnsetPressedState, ViewConfiguration.getPressedStateDuration()); } else if (!post(mUnsetPressedState)) { // If the post failed, unpress right now mUnsetPressedState.run(); } removeTapCallback(); } break; case MotionEvent.ACTION_DOWN: if (mPendingCheckForTap == null) { mPendingCheckForTap = new CheckForTap(); } mPrivateFlags |= PREPRESSED; mHasPerformedLongPress = false; postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); break; case MotionEvent.ACTION_CANCEL: mPrivateFlags &= ~PRESSED; refreshDrawableState(); removeTapCallback(); break; case MotionEvent.ACTION_MOVE: final int x = (int) event.getX(); final int y = (int) event.getY(); // Be lenient about moving outside of buttons int slop = mTouchSlop; if ((x < 0 - slop) || (x >= getWidth() + slop) || (y < 0 - slop) || (y >= getHeight() + slop)) { // Outside button removeTapCallback(); if ((mPrivateFlags & PRESSED) != 0) { // Remove any future long press/tap checks removeLongPressCallback(); // Need to switch from pressed to not pressed mPrivateFlags &= ~PRESSED; refreshDrawableState(); } } break; } return true; } return false; }
在第14行((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
表示如果控件可点击,就会进入判断块内,若当前事件为MotionEvent.ACTION_UP,经过各种if判断,执行38行的performClick(),想必这个方法大家都十分熟悉,只要OnClickListener不为null,内部就调用onClick().
这里需要注意,如果你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action。(这句话看不懂,有知道的小伙伴们解释一下吗?)
onTouch()与onTouchEvent()的区别
- onTouch()优先于onTouchEvent()执行,如果onTouch返回true,则onTouchEvent()得不到执行.onClick()放在在onTouchEvent()内部执行.
- 如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现.
未完待续……
- android事件分发
- android 事件分发
- android事件分发
- android事件分发机制
- Android 事件分发
- Android事件分发机制
- Android 事件分发机制
- Android事件分发机制
- android事件分发
- Android事件的分发
- Android 事件分发机制
- android事件的分发
- Android 事件分发机制
- android 事件分发机制
- Android事件分发机制
- android 事件分发机制
- android事件分发机制
- Android 事件分发
- Android视频开发进阶(part1-关于视频的那些术语)
- Hibernate Annotation配置主键生成策略
- 弹框的一种简单css用法
- eclipse启动tomcat访问不到主页
- 深入oracle的left join中的ON和WHERE的区别详解
- Android事件分发
- Java_构造函数与一般函数的区别
- F1V3.0-11 开发规范——常规模式
- Unity如何限制启动一次实例
- Ce Frumoasa E Iubirea 爱情多美好 罗马尼亚 歌手Giulia
- httpClient及jsoup抓取解析网页数据
- 2017年Android百大框架排行榜
- Codeforces Games
- Spring管理事务默认回滚的异常是什么?