美文网首页
ViewTouch事件以及其传递

ViewTouch事件以及其传递

作者: 大长腿裤子太短 | 来源:发表于2021-12-17 11:15 被阅读0次

面试被问到了一个Button,如果点击无效果,你会怎么排查? 这个问题我当时回答的比较简单,但是面试官追问的比较深,我回答的有些含糊,课后补习一下。

前言:

借鉴了一些简书大佬的文章的文章,然后自己写了Demo,测试完毕后自己总结下自己的理解。


iOS中的事件可以分为3大类型:触摸事件-加速计事件-远程控制事件。

此文只针对触摸事件。

查看源码可以很轻易发现:

UIViewController继承关系 UIView继承关系 UIWindow继承关系 UIApplication继承关系

由此可见:UIViewController - UIView - UIWindow - UIApplication都是继承UIResponder,那UIResponder又是什么呢,图中都继承UIResponder,能代表又有什么结论呢?

先说说UIResponder。

在iOS中UIResponder类是专门用来响应用户的操作处理各种事件的,包括触摸事件(Touch Events)、运动事件(Motion Events)、远程控制事件(Remote Control Events)。具体的UIResponder内部又是如何处理事件,这里不做说明。

查看UIResponder源码可以发现:

UIResponder事件官方

由此可见,官方让我们重新这几个方法,就可以实现触摸相关的活动事件。

UIView,UIApplication,UIWindow,UIViewController继承UIResponder,同样具有父类的这些触摸事件。

这里以UIViewController和UIView为例,其他的道理是相同的。

在UIViewController重新touchesBegan方法,点击当前的Controller,

直接上代码,因为代码比较简单,我就截图说明。

在UIViewController实现touchesBegan方法

触摸事件参数有两个UITouch,UIEvent,两个参数有着自己不同的任务。

UITouch

当用户用一根手指触摸屏幕时,会创建一个与手指相关的UITouch对象.

UITouch对象,封装了当前的Touch事件的对象集合。

UITouchd对象的属性官方介绍

Touch对象保存着跟手指相关的信息,比如触摸的位置、时间、阶段

当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置

当手指离开屏幕时,系统会销毁相应的UITouch对象。

重写:touchesBegan

点击一次,当前操作只有一次,所以Set集合只有一个Touch事件,而且事件tap count = 1。(单击事件)。

重写:touchesMoved

随着手指的拖动,set集合的Touch对象会随之拖到而改变,且此时的Touch对象是不一样的,当前移动的位置和上一次不一样。

正因为手指在不断的移动,所以当前的点和上次移动的点,官方也给了相关方法来获取。

获取当前手指移动和上次移动的点

 UIEvent

UIEvent事件

触摸的目的是生成触摸事件供响应者响应,一个触摸事件(UITouch)对应一个UIEvent对象,其中的type属性标识了事件的类型,事件有如下几种类型:

根据手势的不同操作(单击,滑动,按压,平移等动作),所出发的事件效果会不同。

枚举事件类型

回到前面说的Button的案例。

有个UIButton,Button的点击事件我们也实现了,却点击无效,无法响应与之对应的点击方法,这时候我们该如何去查?

一般都会检查自己写addTarget是否有误,点击事件ButtonClick是否实现。

其次我们也可以从View的事件传递考虑。

View事件传递有三个原则不会传递:

1.当前View或者控件的userInteractionEnabled = NO;

2.当前View或者控件的Hidden为YES

3.同理当前View或者控件透明的<=0.01,也就是(0-0.01)。

除此之外,我们也可以通过重写View的hitTest来查看当前事件可传递的View。

View的hitTest方法

这里使用下比较经典的一个图解:

事件传递

举例:

点击黄色View,因为我们并没有写以上阻断事件传递的三种方式,所以黄色的父控件(蓝色),父父控件(橙色),以及父父父控件(白色)打印的结果都是一直的,指向黄色View。

应用如何找到最合适的控件来处理事件?

1.首先判断主窗口(keyWindow)自己是否能接受触摸事件

2.触摸点是否在自己身上

3.从后往前遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)

4.如果没有符合条件的子控件,那么就认为自己最合适处理

上面的说法是比较官方的解释,用比较通俗的解释就是说:

UIApplication 问 keyWindow :小子,我给你个事件你能不能处理下?

keyWindow唯唯诺诺的说:我。。我不能,触摸点不在我身上。

keyWindow 又去问它的子控件橙色View。

keyWindow:小橙,老大安排了事情,我不能处理,你小子能不能给处理这个点击事件?

OrangeView同样唯唯诺诺的说:我不能,触摸点不在我身上。

。。。。。。

直到最后一层黄色View。

OrangeView:没问题啦~触摸点在我身上,老大们放心吧,我会处理好的(触摸事件里的操作)。

大概用比较欢喜的理解就是这样传递。

特殊情况:

hitTest:withEvent:中return nil的意思是调用当前hitTest:withEvent:方法的view不是合适的view,子控件也不是合适的view。如果同级的兄弟控件也没有合适的view,那么最合适的view就是父控件。

1.所有的子控件都有拦截事件传递的情况,比如都给拦截掉了。

你们他们最终的父控件会返回nil,代表没有其子控件可以处理,只能自己处理了。

子控件打印:

父控件会返回nil情况

父控件打印:

GrayView其实就是上图的1白色,我demo命名不同

代表只能自己去处理这个事件。

其次还需要一点说明,如果1234中的某个view拦截事件了,就不会传递给其子控件啦。

3有拦截事件功能,4就不能操作这个事件,只能是3的父,父父,父父父View来处理。


以上就是我对View事件和传递的自己的理解,记录一下,作为知识点储存。

如果有误或者更好的理解,望大家留言,谢谢。

相关文章

网友评论

      本文标题:ViewTouch事件以及其传递

      本文链接:https://www.haomeiwen.com/subject/bhvvfrtx.html