touch事件与MotionEvent(一)

2024-05-14 00:38
文章标签 事件 touch motionevent

本文主要是介绍touch事件与MotionEvent(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

onInterceptTouchEvent()

返回值说明:
<span style="font-size:24px;">   </span><span style="font-size:18px;">For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().If you return true from here, you will not receive any following events: the target view will receive the same event but with the action {@link MotionEvent#ACTION_CANCEL}, and all further events will be delivered to your onTouchEvent() method and no longer appear here.</span>
       如果返回false,后续事件还会传递到该方法中,经再次判断该方法返回值后,才会传递到子View中。 
       如果返回true,该方法不会接收到任何后续事件,所有的后继事件会直接传递到本View的onTouchEvent()中.但此时target view的事件接收分为两种情况:如果target view从来没有接收到该事件,那么仍旧不会接收到任何事件;如果target view曾经接收到过该事件,那么还会再一次,且仅一次地接收到该事件,只不过action为action_cancel。

OnTouchEvent():

       如果返回true,就不会执行父View的onTouchEvent()方法,代表着本次touch事件子View进行处理,父View不需要插手。
       如果返回false,在执行完子View的onTouchEvent()方法后还会执行父View的onTouchEvent()方法,此时事件是从子View往父View传递。返回false时,touch的后继事件不会传递到View的onTouchEvent()和onInterceptTouchEvent()中,即使父View的onInterceptTouchEvent()仍旧返回的是false,这个touch事件已经与子View没有任何关系了。

onTouch与onIntercept的返回值的四种情况

        (1)、onTouchEvent()返回false,onInterceptTouchEvent()返回true
        后续事件不会传递到子View、onIntercept与onTouch中.因为intercept返回true后,方法不会传递到子View以及intercept中;而touch又返回false,所以事件也不会传递到onTouch中。
(2)、onTouchEvent()返回true,onInterceptTouchEvent()返回true:
       后续事件不会传递到子View和onInterceptTouchEvent中,只会传递到onTouchEvent()中。
(3)、onTouchEvent()返回false,onInterceptTouchEvent()返回false:
       后续事件会走到intercept方法与子View中。但是不会走到本View的onTouchEvent中。
(4)、onTouchEvent()返回true,onInterceptTouchEvent()返回false:
       后续事件会走到intercept方法与子View中。但是不会走到本View的onTouchEvent中。

View#dispatchTouchEvent():

它在View.java中的源码为:

 public boolean dispatchTouchEvent(MotionEvent event) {if (!onFilterTouchEventForSecurity(event)) {return false;}if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&mOnTouchListener.onTouch(this, event)) {return true;}return onTouchEvent(event);}

       从上面可以看出,setOnTouchEventListener()要优先于onTouchEvent()执行。而且touchListener如果返回为true的话,就不会再执行onTouchEvent()了

      并且该方法的主要作用是:把事件分发到onTouchEventListener和onTouchEvent()中。并不是用来决定事件要不要分发到子View中。

onLongClick,onClick与onTouch():

在View.java(安卓版本为2.2)文件中,它的onTouchEvent()代码片段为:

case MotionEvent.ACTION_DOWN:if (mPendingCheckForTap == null) {mPendingCheckForTap = new CheckForTap();}mPrivateFlags |= PREPRESSED;mHasPerformedLongPress = false;postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());break;
其中最后一句代码会延迟执行CheckForTap(),它的源码是:
 private final class CheckForTap implements Runnable {public void run() {mPrivateFlags &= ~PREPRESSED;mPrivateFlags |= PRESSED;refreshDrawableState();if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {postCheckForLongClick(ViewConfiguration.getTapTimeout());}}}
而postCheckForLongClick()的源代码为:
 private void postCheckForLongClick(int delayOffset) {mHasPerformedLongPress = false;if (mPendingCheckForLongPress == null) {mPendingCheckForLongPress = new CheckForLongPress();}mPendingCheckForLongPress.rememberWindowAttachCount();postDelayed(mPendingCheckForLongPress,ViewConfiguration.getLongPressTimeout() - delayOffset);}
而CheckForLongPress的run()方法中又会调用到performLongClick(),其片段为:
 if (performLongClick()) {mHasPerformedLongPress = true;}
而performLongClick()的源码为
 public boolean performLongClick() {sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);boolean handled = false;if (mOnLongClickListener != null) {handled = mOnLongClickListener.onLongClick(View.this);}if (!handled) {handled = showContextMenu();}if (handled) {performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);}return handled;}
这里终于调用了onLongClick()方法。

       从上面可以看出:在ACTION_DOWN的时候,已经受理了onLongClick,只不过是延迟处理。

再看onTouchEvent()中的ACTION_UP

if (!mHasPerformedLongPress) {// This is a tap, so remove the longpress checkremoveLongPressCallback();// Only perform take click actions if we were in the pressed stateif (!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();}}}
       其中会调用到performClick(),它里面就会调用onClick()。因此,onClick只是在ACTION_UP事件之后才会触发。同时,它有一个前提条件:mHasPerformedLongPress为false。如果mHasPerformedLongPress为true,就不会发生onClick事件。我们可以发现在整个View.java中,只有performLongClick()返回true时,mHasPerformedLongPress才会被赋值为true。同时,通过performLongClick()的源码,可以知道,performLongClick()的返回值就是onLongClick()的返回值。因此,当onLongClick返回true时,就不会执行onClick();如果返回false,就会执行

        longClick是从down事件开始的,click是up事件中执行的。因此,如果接收不到up事件,不会执行click事件。longClick返回true,也不会执行click事件;反之则会执行

click与longclick对onTouchEvent()返回值的要求

       由于click事件是ACTION_UP时才触发的,所以action_up之前onTouchEvent()必须返回true,但action_up时可以返回false。

       而longclick是在action_down中受理并延迟执行的,所以它对onTouchEvent()的返回值没有要求。只不过在action_up,action_cancel和action_move(move时移出view范围)时会取消对longclick的执行。因此,如果在down时如果返回false,那么longclick肯定会执行。

MotionEvent

        处理触摸事件时,经常需要重写onTouchEvent(),而传入该方法中的参数就代表着本次事件。并且可以支持多指触摸与单指触摸。

常用常量

        这些常量表示着当前事件的类型。

        ACTION_DOWN:第一根手指触摸发生down事件时。
        ACTION_POINTER_DOWN:非第一根手指发生down事件时。
        ACTION_UP:最后一根手指发生抬起时。
        ACTION_POINTER_UP:非最后一根手指抬起时。
        ACTION_MOVE:无论哪根手指移动,都会走该case。

常用方法

        getActioniMasked():获取当前事件类型。处理多指触摸获取事件类型时,必须使用该方法,否则返回的类型不会有ACTION_POINTER_DOWN。简单一句话:判断事件类型用getActionMasked()而不是getAction()

        getPointerCount():获取当前触摸的手指数。从0到getPointerCount()-1的值就是pointerIndex。getX,getY()等函数也可传入pointerIndex,用于获取指定手指的x,y坐标。
        getPointerId():根据pointerIndex获取pointerId。
        findPointerIndex():根据pointerId获取pointerIndex。
        getActionIndex():获取当前触发事件的手指的pointerIndex。

参考

可以参考stackoverflow。

        一般来说,多指触摸时,首先根据getActionIndex()得到当前事件手指的pointerIndex,再得到pointerId,最后在使用时由id得到index






这篇关于touch事件与MotionEvent(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/987259

相关文章

Python中的异步:async 和 await以及操作中的事件循环、回调和异常

《Python中的异步:async和await以及操作中的事件循环、回调和异常》在现代编程中,异步操作在处理I/O密集型任务时,可以显著提高程序的性能和响应速度,Python提供了asyn... 目录引言什么是异步操作?python 中的异步编程基础async 和 await 关键字asyncio 模块理论

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

【经验交流】修复系统事件查看器启动不能时出现的4201错误

方法1,取得『%SystemRoot%\LogFiles』文件夹和『%SystemRoot%\System32\wbem』文件夹的权限(包括这两个文件夹的所有子文件夹的权限),简单点说,就是使你当前的帐户拥有这两个文件夹以及它们的子文件夹的绝对控制权限。这是最简单的方法,不少老外说,这样一弄,倒是解决了问题。不过对我的系统,没用; 方法2,以不带网络的安全模式启动,运行命令行,输入“ne

BT天堂网站挂马事件后续:“大灰狼”远控木马分析及幕后真凶调查

9月初安全团队披露bt天堂网站挂马事件,该网站被利用IE神洞CVE-2014-6332挂马,如果用户没有打补丁或开启安全软件防护,电脑会自动下载执行大灰狼远控木马程序。 鉴于bt天堂电影下载网站访问量巨大,此次挂马事件受害者甚众,安全团队专门针对该木马进行严密监控,并对其幕后真凶进行了深入调查。 一、“大灰狼”的伪装 以下是10月30日一天内大灰狼远控的木马样本截图,可以看到该木马变种数量不

react笔记 8-19 事件对象、获取dom元素、双向绑定

1、事件对象event 通过事件的event对象获取它的dom元素 run=(event)=>{event.target.style="background:yellowgreen" //event的父级为他本身event.target.getAttribute("aid") //这样便获取到了它的自定义属性aid}render() {return (<div><h2>{

react笔记 8-18 事件 方法 定义方法 获取/改变数据 传值

1、定义方法并绑定 class News extends React.Component {constructor(props) {super(props)this.state = {msg:'home组件'}}run(){alert("我是一个run") //方法写在类中}render() {return (<div><h2>{this.state.msg}</h2><button onCli

【Qt】定时器事件

定时器事件 在之前学习QTimer中实现了定时器的功能,而在QTimer背后是QTimerEvent定时器事件进行支撑的。在QObject中提供了一个timeEvent这个函数。 startTimer启动定时器killTimer关闭定时器 Qt 中在进⾏窗⼝程序的处理过程中,经常要周期性的执⾏某些操作,或者制作⼀些动画效果,使⽤定 时器就可以实现。所谓定时器就是在间隔⼀定时间后,去执⾏某⼀

Imageview在百度地图中实现点击事件

1.首先第一步,需要声明的全局有关类的引用 private BMapManager mBMapMan; private MapView mMapView; private MapController mMapController; private RadioGroup radiogroup; private RadioButton normalview; private RadioBu

Winform中在窗体中的Paint事件中重绘会导致递归问题?

在 WinForms 应用程序中,如果在窗体的 Paint 事件处理程序中不断调用 Invalidate 方法,确实可能会导致递归调用的问题。这是因为每次调用 Invalidate 方法时,都会向消息队列添加一个绘制消息,当消息队列中的绘制消息被处理时,会触发 Paint 事件。如果 Paint 事件处理程序中又调用了 Invalidate,就会形成一个循环,导致递归调用 Paint 事件,这