i事件的产生传递响应俊华的博客

注 意: 如果父控件不能接受触摸事件,那么子控件就不可能接收到触摸事件

注 意:默认UIImageView不能接受触摸事件,因为不允许交互,即userInteractionEnabled = NO,所以如果希望UIImageView可以交互,需要userInteractionEnabled = YES。

应用如何找到最合适的控件来处理事件?1.首先判断主窗口(keyWindow)自己是否能接受触摸事件2.触摸点是否在自己身上3.从后往前遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)4.如果没有符合条件的子控件,那么就认为自己最合适处理

详述:1.主窗口接收到应用程序传递过来的事件后,首先判断自己能否接手触摸事件。如果能,那么在判断触摸点在不在窗口自己身上   2.如果触摸点也在窗口身上,那么窗口会从后往前遍历自己的子控件(遍历自己的子控件只是为了寻找出来最合适的view)   3.遍历到每一个子控件后,又会重复上面的两个步骤(传递事件给子控件,1.判断子控件能否接受事件,2.点在不在子控件上)   4.如此循环遍历子控件,直到找到最合适的view,如果没有更合适的子控件,那么自己就成为最合适的view。找到最合适的view后,就会调用该view的touches方法处理具体的事件。所以,只有找到最合适的view,把事件传递给最合适的view后,才会调用touches方法进行接下来的事件处理。找不到最合适的view,就不会调用touches方法进行事件处理。注意:之所以会采取从后往前遍历子控件的方式寻找最合适的view只是为了做一些循环优化。因为相比较之下,后添加的view在上面,降低循环次数。

hitTest:withEvent:方法pointInside方法

什么时候调用?

作用:

拦截事件的处理

hitTest:withEvent:方法中返回nil

hitTest:withEvent:方法中返回nil,那么调用该方法的控件本身和其子控件都不是最合适的view,也就是在自己身上没有找到更合适的view。那么最合适的view就是该控件的父控件。

事件的传递顺序是这样的:

产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回更合适的view->[子控件 hitTest:withEvent:]->返回最合适的view

注意:不管子控件是不是最合适的view,系统默认都要先把事件传递给子控件,经过子控件调用自己的hitTest:withEvent:方法验证后才知道有没有更合适的view。

实践中遇到的问题:1.想让谁成为最合适的view的方法  2.当遍历子控件时,如果触摸点不在子控件A自己身上而是在子控件B身上,还要要求返回子控件A作为最合适的view

解决方案

特殊情况:1.谁都不能处理事件,窗口也不能处理。

2.只能有窗口处理事件。

寻找最合适的view底层剖析之hitTest:withEvent:方法底层做法

/** hitTest:withEvent:方法底层实现**/

hitTest:withEvent:方法底层会调用pointInside:withEvent:方法判断点在不在方法调用者的坐标系上。

pointInside:withEvent:方法判断点在不在当前view上(方法调用者的坐标系上)如果返回YES,代表点在方法调用者的坐标系上;返回NO代表点不在方法调用者的坐标系上,那么方法调用者也就不能处理事件。

1>用户点击屏幕后产生的一个触摸事件,经过一系列的传递过程后,会找到最合适的视图控件来处理这个事件2>找到最合适的视图控件后,就会调用控件的touches方法来作具体的事件处理touchesBegan…touchesMoved…touchedEnded…3>这些touches方法的默认做法是将事件顺着响应者链条向上传递(也就是touch方法默认不处理事件,只传递事件),将事件交给上一个响应者进行处理

响应者链条:在iOS程序中无论是最后面的UIWindow还是最前面的某个按钮,它们的摆放是有前后关系的,一个控件可以放到另一个控件上面或下面,那么用户点击某个控件时是触发上面的控件还是下面的控件呢,这种先后关系构成一个链条就叫“响应者链”。也可以说,响应者链是由多个响应者对象连接起来的链条。在iOS中响应者链的关系可以用下图表示:

事件的响应(即找到合适的view后事件的处理 touchBegin)

1.最合适的view的touchBegin 不处理就给上一层

2.事件的默认是调用super 的

响应者对象:能处理事件的对象,也就是继承自UIResponder的对象

作用:能很清楚的看见每个响应者之间的联系,并且可以让一个事件多个对象处理。

如何判断上一个响应者

响应者链的事件传递过程:

事件的传递与响应

1、当一个事件发生后,事件会从父控件传给子控件,也就是说由UIApplication -> UIWindow -> UIView -> initial view,以上就是事件的传递,也就是寻找最合适的view的过程。

2、接下来是事件的响应。首先看initial view能否处理这个事件,如果不能则会将事件传递给其上级视图(inital view的superView);如果上级视图仍然无法处理则会继续往上传递;一直传递到视图控制器view controller,首先判断视图控制器的根视图view是否能处理此事件;如果不能则接着判断该视图控制器能否处理此事件,如果还是不能则继续向上传 递;(对于第二个图视图控制器本身还在另一个视图控制器中,则继续交给父视图控制器的根视图,如果根视图不能处理则交给父视图控制器处理);一直到 window,如果window还是不能处理此事件则继续交给application处理,如果最后application还是不能处理此事件则将其丢弃

3、在事件的响应中,如果某个控件实现了touches...方法,则这个事件将由该控件来接受,如果调用了[supertouches….];就会将事件顺着响应者链条往上传递,传递给上一个响应者;接着就会调用上一个响应者的touches….方法

如何做到一个事件多个对象处理:因为系统默认做法是把事件上抛给父控件,所以可以通过重写自己的touches方法和父控件的touches方法来达到一个事件多个对象处理的目的。

事件的传递和响应的区别:事件的传递(拿到最合适的view)是从上到下(父控件到子控件),事件的响应(拿到最合适的view 处理事件)是从下到上(顺着响应者链条向上传递:子控件到父控件)。

iOS中的事件可以分为3大类型:

响应者对象(UIResponder)

1.能处理事件的对象叫做响应者对象

在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接受并处理事件,我们称之为“响应者对象”。

以下都是继承自UIResponder的,所以都能接收并处理事件。

2.那么为什么继承自UIResponder的类就能够接收并处理事件呢?

因为UIResponder中提供了以下4个对象方法来处理触摸事件

需要注意的是:以上四个方法是由系统自动调用的,所以可以通过重写该方法来处理一些事件。

3.想处理UIView的触摸事件,必须自定义UIView子类继承自UIView

如何实现UIView的拖拽呢?也就是让UIView随着手指的移动而移动。- 重写touchsMoved:withEvent:方法(代码如下)

一根手指对应一个UITouch对象

如果两根手指同时触摸一个view,那么view只会调用一次touchesBegan:withEvent:方法,touches参数中装着2个UITouch对象

THE END
0.这五款智能黑科技产品别犹豫,趁双十二赶快上车!|蓝牙耳机|充电器|除此之外,AirPods Pro还有一个大亮点,那就是锁耳设计,可以在运动或者奔跑时,不会出现掉落的情况。 苹果蓝牙耳机一直都是行业的领导者,技术永远被模仿,但无法被超越。AirPods Pro强大的科技体验感,目前双十二期间到手1799元,用它送女朋友在再适合不过了。 荣耀智能手表2代 荣耀智能手表2代分为碳石黑、亚麻棕、玛瑙黑、樱粉jvzquC41f{428<3eqo5bt}neng5GVAFK7W:17:6C87>/j}rn
1.Qt多线程1:QThreadqtqthread如果QThread是在ui所在的线程里生成,那么QThread的其他非run函数都是和ui线程一样的,所以,QThread的继承类的其他函数尽量别要有太耗时的操作,要确保所有耗时的操作都在run函数里。 在UI线程下调用QThread的非run函数(其实也不应该直接调用run函数,而应该使用start函数),和执行普通函数无区别,这时,如果这个函数要对jvzquC41dnuh0lxfp0tfv8my74911jwvkerf1mjvckrt1:83249:39
2.2022前端面试题mobx面试题路由分为前端路由和后端路由,后端路由是服务器根据用户发起的请求而返回不同内容,前端路由是客户端根据不同的URL去切换组件;在web应用前端开发中,路由系统是最核心的部分,当页面的URL发生改变时,页面的显示结果可以根据URL的变化而变化,但是页面不会刷新。 react生态中路由通常是使用react-router来进行配置,其主要jvzquC41dnuh0lxfp0tfv8}kcqjfd~kw{ct0c{ykenk0fnyckny03;:292793
3.iOS10适配汇总有点晕,不是么?一个开发者很难在不借助于文档的帮助下区分 application(_:didReceiveRemoteNotification:) 和 application(_:didReceiveRemoteNotification:fetchCompletionHandle:),新入行的开发者也不可能明白 registerForRemoteNotificationTypes 和 registerUserNotificationSettings(_:) 之间是不是有什么关系,Remote 和 LocjvzquC41dnuh0lxfp0tfv8jcpmngwlngkhmqp4ctvodnn4fgvgjn|4747>43?5
4.[前端面试]vue八股前端八股vmodel比如说:我们在data中声明了一个对象person,但是在后期为person增加了新的属性,那么这个新的属性就会失去响应性。想要解决这个问题其实也非常的简单,可以通过Vue.$set方法来增加指定对象指定属性的响应性。但是这样的一种方式,在Vue的自动响应性机制中是不合理。 jvzquC41dnuh0lxfp0tfv8vsa99399<421gsvrhng1jfvjnnu1756957:5;
5.QT学习使用多线程的两种方法(子类化QThread+子类化QObject)本文的重点不是教会你继承run写一个多线程,任何有编程基础的5分钟就能学会使用QThread的方法,本文真正要讲的是后面那几节,如如何安全的退出一个线程,如何开启一个临时线程,运行结束马上关闭等问题。如果你对QThread有初步了解,那么可以略过这节,但你最好看看这节后面提出的几个问题。 jvzquC41dnuh0lxfp0tfv8z234984>=61cxuklqg1fkucrqu1:662B739