面试题答案
一键面试1. 事件传递机制概述
在Objective-C中,当触摸事件发生时,系统会从应用程序的主窗口开始,按照一定的规则寻找最合适的视图来处理这个事件。这个过程基于视图的层级关系以及视图的属性(如是否可交互、是否隐藏、透明度等)。
2. 确定响应视图的规则
- 窗口首先接收事件:应用程序的主窗口是事件传递的起点。UIWindow会将事件传递给它的
rootViewController
的视图。 - 视图层级遍历:系统会从父视图开始,递归地询问每个子视图是否能够处理该事件。询问的依据主要是
hitTest:withEvent:
方法。该方法首先判断自身是否能接收触摸事件(通过userInteractionEnabled
是否为YES
、hidden
是否为NO
、alpha
是否大于0.01等条件),如果不能则直接返回nil
。如果能接收,会遍历它的子视图,从后往前(即最上层的子视图先被询问)调用子视图的hitTest:withEvent:
方法。如果某个子视图返回非nil
,则该子视图就是最合适的视图,否则自身就是最合适的视图并返回自身。 - 最终确定响应者:通过上述遍历,最终会确定一个最合适的视图来响应事件,这个视图就是
hitTest:withEvent:
方法返回的视图。
3. 响应链流程
- 初始响应者:当触摸事件发生在自定义控件上,该自定义控件成为初始响应者。
- 向上传递:如果初始响应者不能处理该事件,它会将事件沿着响应链向上传递。响应链的顺序是:视图 -> 父视图 -> 视图控制器 -> 父视图控制器 -> … -> UIWindow -> UIApplication。
- 寻找处理者:沿着响应链,每个对象都有机会处理事件。如果某个对象能够处理事件,事件处理就会在这里结束。如果一直传递到
UIApplication
都没有对象处理事件,事件就会被忽略。
4. 自定义控件内多个子视图时控制事件传递与响应
- 重写
hitTest:withEvent:
方法:在自定义控件类中重写hitTest:withEvent:
方法,可以根据业务需求自定义事件传递逻辑。例如,可以根据触摸点的位置在子视图间进行更精细的判断,或者根据某些条件直接返回特定的子视图。 - 设置子视图属性:通过设置子视图的
userInteractionEnabled
属性为NO
,可以阻止子视图接收触摸事件,这样事件就会传递给自定义控件或其他符合条件的视图。 - 手势识别器:可以为子视图或自定义控件添加手势识别器(UIGestureRecognizer)。手势识别器可以在触摸事件传递到视图的
touches
方法之前捕获并处理事件,从而实现对事件的拦截和处理。例如,可以通过添加UITapGestureRecognizer
来处理点击事件,并且可以设置手势识别器的代理方法,进一步控制事件的处理逻辑。