View源码-Touch事件
在Android-27中查看源码:
首先我们来查看单个View的触摸事件的处理,在View的dispatchTouchEvent方法中看看源码是如何处理的。
public boolean dispatchTouchEvent(MotionEvent event) {
// If the event should be handled by accessibility focus first.
if (event.isTargetAccessibilityFocus()) {
// We don't have focus or no virtual descendant has it, do not handle the event.
if (!isAccessibilityFocusedViewOrHost()) {
return false;
}
// We have focus and got the event, then use normal event dispatch.
event.setTargetAccessibilityFocus(false);
}
boolean result = false;
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Defensive cleanup for new gesture
stopNestedScroll();
}
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//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;
}
}
if (!result && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
// Clean up after nested scrolls if this is the end of a gesture;
// also cancel it if we tried an ACTION_DOWN but we didn't want the rest
// of the gesture.
if (actionMasked == MotionEvent.ACTION_UP ||
actionMasked == MotionEvent.ACTION_CANCEL ||
(actionMasked == MotionEvent.ACTION_DOWN && !result)) {
stopNestedScroll();
}
return result;
}
dispatchTouchEvent处理过程如下:
- 如果设置了OnTouchListener和enabled为true,并且onTouch返回为true,即该View在OnTouchListener的onTouch方法中处理了触摸事件。
- 如果onTouchEvent返回为true,即该View在onTouchEvent中处理了触摸事件。
- 如果触摸事件在该View中得到处理则返回true,否则返回false(即该View对触摸事件不予处理)。
接下来查看onTouchEvent方法的源码:
public boolean onTouchEvent(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
final int viewFlags = mViewFlags;
final int action = event.getAction();
final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
setPressed(false);
}
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
// A disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return clickable;
}
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
if ((viewFlags & TOOLTIP) == TOOLTIP) {
handleTooltipUp();
}
if (!clickable) {
removeTapCallback();
removeLongPressCallback();
mInContextButtonPress = false;
mHasPerformedLongPress = false;
mIgnoreNextUpEvent = false;
break;
}
boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
if ((mPrivateFlags & PFLAG_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 (prepressed) {
// The button is being released before we actually
// showed it as pressed. Make it show the pressed
// state now (before scheduling the click) to ensure
// the user sees it.
setPressed(true, x, y);
}
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
// 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) {
postDelayed(mUnsetPressedState,
ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
removeTapCallback();
}
mIgnoreNextUpEvent = false;
break;
case MotionEvent.ACTION_DOWN:
if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
mPrivateFlags3 |= PFLAG3_FINGER_DOWN;
}
mHasPerformedLongPress = false;
if (!clickable) {
checkForLongClick(0, x, y);
break;
}
if (performButtonActionOnTouchDown(event)) {
break;
}
// Walk up the hierarchy to determine if we're inside a scrolling container.
boolean isInScrollingContainer = isInScrollingContainer();
// For views inside a scrolling container, delay the pressed feedback for
// a short period in case this is a scroll.
if (isInScrollingContainer) {
mPrivateFlags |= PFLAG_PREPRESSED;
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
mPendingCheckForTap.x = event.getX();
mPendingCheckForTap.y = event.getY();
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
// Not inside a scrolling container, so show the feedback right away
setPressed(true, x, y);
checkForLongClick(0, x, y);
}
break;
case MotionEvent.ACTION_CANCEL:
if (clickable) {
setPressed(false);
}
removeTapCallback();
removeLongPressCallback();
mInContextButtonPress = false;
mHasPerformedLongPress = false;
mIgnoreNextUpEvent = false;
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
break;
case MotionEvent.ACTION_MOVE:
if (clickable) {
drawableHotspotChanged(x, y);
}
// Be lenient about moving outside of buttons
if (!pointInView(x, y, mTouchSlop)) {
// Outside button
// Remove any future long press/tap checks
removeTapCallback();
removeLongPressCallback();
if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
setPressed(false);
}
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
}
break;
}
return true;
}
return false;
}
onTouchEvent里面的处理如下:
- 如果setEnabled(false),则返回false,即该View对触摸事件不予处理。
- 如果设置了TouchDelegate,并且TouchDelegate的onTouchEvent返回true,则返回true,即由TouchDelegate中的onTouchEvent方法处理了触摸事件。否则继续向下。
- 如果该View不可点击并且(viewFlags & TOOLTIP) != TOOLTIP(即当停留或长按在该view时不可显示提示框),则返回false,即该View对触摸事件不予处理。否则继续向下。
根据触摸事件的分类进行处理:
MotionEvent.ACTION_DOWN:
- 不可点击或者不在可滑动的容器内:如果LONG_CLICKABLE为true则执行OnLongClickListener的onLongClick方法;或者设置了viewFlags为TOOLTIP,则执行showTooltip(显示提示框)。然后返回true,即该View处理了触摸事件,否则继续向下走。
- MotionEvent.ACTION_MOVE:在手指移动的过程中判断是否仍在当前view的范围。
MotionEvent.ACTION_UP:
- 显示了提示框的话则隐藏;
- 如果不可点击,则移除长按事件的检测,返回true,否则继续向下走。
- 当前是点击事件,所以移除长按事件的检测。然后执行performClick方法,返回true,即该View处理了触摸事件。
关于ViewGroup源码中的Touch事件,可以参考文章:ViewGroup源码-Touch事件
View源码-Touch事件的更多相关文章
- Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制
转自:xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/21696315) 今天这篇文章主要分析的是Android的事件分发机制, ...
- View,ViewGroup的Touch事件的分发机制
原帖地址:http://blog.csdn.net/xiaanming/article/details/21696315 ViewGroup的事件分发机制 我们用手指去触摸Android手机屏幕,就会 ...
- Android必学-异步加载+Android自定义View源码【申明:来源于网络】
Android必学-异步加载+Android自定义View源码[申明:来源于网络] 异步加载地址:http://download.csdn.net/detail/u013792369/8867609 ...
- CBV流程之View源码解析
CBV是基于反射实现根据请求方式不同,执行不同的方法. 请求流程:view源码解析 1.urls.py :请求一定来执行视图下的as_view方法.也可以直接点击as_view()来找源码. 2.vi ...
- DRF(1) - REST、DRF(View源码解读、APIView源码解读)
一.REST 1.什么是编程? 数据结构和算法的结合. 2.什么是REST? 首先回顾我们曾经做过的图书管理系统,我们是这样设计url的,如下: /books/ /get_all_books/ 访问所 ...
- REST、DRF(View源码解读、APIView源码解读)
一 . REST 前言 1 . 编程 : 数据结构和算法的结合 .小程序如简单的计算器,我们输入初始数据,经过计算,得到最终的数据,这个过程中,初始数据和结果数据都是数据,而计算 ...
- Restful 1 -- REST、DRF(View源码解读、APIView源码解读)及框架实现
一.REST 1.什么是编程? 数据结构和算法的结合 2.什么是REST? - url用来唯一定位资源,http请求方式来区分用户行为 首先回顾我们曾经做过的图书管理系统,我们是这样设计url的,如下 ...
- Spark2.1.0之源码分析——事件总线
阅读提示:阅读本文前,最好先阅读<Spark2.1.0之源码分析——事件总线>.<Spark2.1.0事件总线分析——ListenerBus的继承体系>及<Spark2. ...
- 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案 | 百篇博客分析OpenHarmony源码 | v30.02
百篇博客系列篇.本篇为: v30.xx 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当 ...
随机推荐
- HDU 3150 Robot Roll Call – Cambot…Servo…Gypsy…Croooow(map)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3150 Problem Description Mystery Science Theater 3000 ...
- haifeng
[root@localhost 桌面]# yum list|grep wubi ibus-table-chinese-wubi-haifeng.noarch -.el7 base ibus-table ...
- 百科知识 国内的创业项目如何众筹,能登录Kickstarter吗
一个国内的团队登陆Kickstarter到底有多难? 300万用户,4.8亿美元筹款,Kickstarter在2013年交出了一份惊艳的答卷.对于美英澳加新荷六国的创业团队来说,Kickstarter ...
- Python & Django & Pycharm 安装
一.下载安装Python 从https://www.python.org/上下载 Python 2.7.6,双击安装包开始安装: 单击“Next”按钮,进入Python安装组件选择界面.这里我们安装全 ...
- eclipse 安装java web插件
1.eclipse java web搭建以及tomcat配置: http://www.cnblogs.com/yangyxd/articles/5615965.html 注意选择Eclipse IDE ...
- [LeetCode] Decode Ways 解码方法个数、动态规划
A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' - ...
- win7 iis6怎么部署.net网站
win7 iis6怎么部署.net网站,把本机当成网站服务器来简单介绍. 方法/步骤 1 首先在本机有一个可以正常运行的网站.比如vs2010中有一个网站项目,网站项目运行后正常. 2 打开iis6, ...
- BFC简析
一.BOX模型 box是CSS中布局的基本单位,而不同类型的box,会参与不同的Formatting Context(一个决定如何渲染文档的容器),box内的元素会以不同的方式渲染. block-le ...
- Android setTag()与getTag(),与set多个setTag()
首先我们要知道setTag方法是干什么的,SDK解释为 Tags Unlike IDs, tags are not used to identify views. Tags are essential ...
- mysql 5.5主从复制配置
首先将主库现有的要实现主从的数据库原原本本地复制到从库上,目的是一开始就让主从同步,让binlog日志从最新的记录开始同步! 备份: 方法1:快捷导出所要的库如(库goods)[注意:该方法仅适合My ...