Android触屏分发机制(一)
来源:互联网 发布:天刀冰云染色数据 编辑:程序博客网 时间:2024/06/08 17:40
面试学校工作室HCI时曾被要求写类似知乎的界面逻辑,其中遇到了一个问题就是layout的onTouch和button的onClick冲突,解决的方法便是了解触屏分发机制。这段时间查阅了许多资料,具体了解Android的触屏分发机制是怎么实现的。
按钮的点击事件相信大家闭着眼睛都能写得出来了:
btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.i(TAG, "on click"); } });
如果说再给这个按钮添加一个onTouch事件,会输出怎样的结果呢?
btn.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.i(TAG, "on touch action down"); break; case MotionEvent.ACTION_UP: Log.i(TAG, "on touch action up"); break; } return false; } });
以下是输出结果:
可以看出,onTouch时间是在onclick之前执行的。我们可能会发现onTouch的方法中有一个返回值false,如果把它改为true,结果会怎样?
此时Button的onClick事件并没有执行!我们可以这样理解,当onTouch时间返回true时,相当于把当前的点击事件消费(拦截)掉了,从而无法把点击事件继续分发下去。那为什么会因为一个返回值而导致结果不同呢?其中View有一个重要的方法dispatchTouchEvent()可以解释其中的原因,当按钮点击时,会首先执行dispatchTouchEvent()这个方法。从字面的意思上理解dispatch有调度,分发的意思,按钮点击后则在这个方法中分发事件。往上查找,我们会发现View中有这个方法,我们看看其方法的主要部分:
public boolean dispatchTouchEvent(MotionEvent event) { //省略一部分 if (onFilterTouchEventForSecurity(event)) { //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; } } //省略一部分 return result; }
我们看看第二个if里的三个参数,
mListenerInfo:这个是我们在为Button设置onTouch事件时传递的参数,即new View.OnTouchListener(){//…},这个值不为null;
第二个参数则是判断按钮是否可用。
第三个参数li.mOnTouchListener.onTouch(this, event)为onTouch事件的返回值。
明显,当第三个参数返回为true时,result = true,否则为false。接着看下一个if语句,意思为当result为false时则执行onTouchEvent(event)这个方法,并赋值result;可见我们的onTouch事件的返回值为false时会执行onTouchEvent(event)方法。那我们在看看onTouchEvent方法是如何实现的:
public boolean onTouchEvent(MotionEvent event) { //省略一部分 if (!focusTaken) { if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { performClick(); } } //省略一部分 }
其中经过种种判断(由于代码过长,就没有贴出来了),会进入performClick()这个方法:
public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); return result; }
明显,我们可以看到在第6行执行了onClick事件,而mListenerInfo正是我们在为按钮添加onClick事件时传入的参数!
因此,我们可以总结一下点击按钮后事件是如何分发的:
Android触屏分发机制(二)http://blog.csdn.net/u010429311/article/details/50979578
- Android触屏分发机制(一)
- Android触屏分发机制(二)
- 系列(一) Android 事件分发机制
- Android事件分发机制(一)
- Android事件分发机制详解(一)
- Android中的事件分发机制(一)
- Android事件分发机制(一)
- Android----View事件分发机制(一)
- Android事件分发机制(一)
- Android事件分发机制(一)
- Android事件分发机制(一)
- android 事件分发机制详解(一)
- Android事件分发机制(一)
- android 事件分发机制一
- android事件分发机制一
- Android事件分发机制一
- Android事件分发机制(一) Touch 事件的分发和消费机制
- Android触屏事件分发机制
- 框模型中的外边距合并问题
- 23.获取两个时间的自然天数间隔
- 正则表达式
- Java 8的新特性—终极版
- sqlite3-递归查询
- Android触屏分发机制(一)
- 简历编写规则
- 【c/c++】字符串相关操作
- 静态成员
- SpringMVC手动配置
- udev的使用-minicom没有权限打开串口,更改 ttyUSB0 的权限
- 【慕课笔记】1-5 初涉MYSQL—修改MYSQL提示符
- UML
- SQLite学习手册(数据库和事务)