这是我参与「第四届青训营 」笔记创作活动的的第13天
iOS 交互、手势与动画编程(上)| 青训营笔记
对课程讲解内容进行重新编排,从最核心的事件机制开始,后面再实战举例。
iOS 事件响应机制
iOS 事件类型
- 触摸事件
- 运动事件(加速计)
- 远程操控事件(手柄)
iOS事件核心类:以触摸为例
UITouch:触摸对象,触摸时产生,用于记录单个手指的触摸事件
- 当用户触摸屏幕时,系统会创建一个UITouch集合(一根手指对应一个UITouch对象,该对象保存触摸事件的信息,如触摸的位置、时间、阶段等)
- 当用户移动手指时,系统会更新每个手指对应的UITouch对象保存的信息
- 当用户将手指离开屏幕时,系统会销毁相应的UITouch对象
UIEvent:触摸事件,用于记录一个完整的触摸过程
- 记录产生的时刻和类型
- 记录当前多点触摸序列相对应的所有触摸对象
- 提供与特定视图或窗口相关联的触摸对象
UIResponder:用于处理事件
可以通过4个处理触摸事件的方法处理事件
//手指触碰屏幕,触摸开始
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
//手指在屏幕上移动
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
//手指离开屏幕,触摸结束
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
//触摸结束前,某个系统事件中断了触摸,例如电话呼入
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
事件传递和响应链
事件传递
- 发生触摸事件后,系统将事件加入到 UIApplication*管理的事件队列中
- UIApplication从事件队列中取出最前面的事件,并将其分发下去处理,通常先发送事件给应用程序的主窗口keyWindow;
- keyWindow 会在视图层次结构中, 找到一个最适合的视图第一响应者First responder来处理触摸事件(命中测试hitTest:withEvent)
- hitTest:withEvent判断响应者
- 判断自身是否能够响应:userlnteractionEnabled、hidden、alpha
- 判断触摸点是否在自己frame范围内 (pointinside : withEvent )
- 由上到下遍历自己的子视图递归调用该方法,判断是否有返回view
- 如果子视图都没有能力响应,返回自己
响应链:responder chain
UIEvent作为事件的消息载体在响应链responder chain上传递,第一响应者First responder处理完后交给下一响应者Next responder,由上到下响应
详解 iOS 手势识别器
常用手势
- UITapGestureRecognizer(触摸点按)
- UIPanGestureRecognizer(拖动)
- UIPinchGestureRecognizer(捏合)
- UIRotationGestureRecognizer(旋转)
- UILongPressGestureRecognizer(长按)
- UISwipeGestureRecognizer(轻扫)
手势状态
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) { UIGestureRecognizerStatePossible, // 尚未识别是何种手势操作(但可能已经触发了触摸事件),默认状态
UIGestureRecognizerStateBegan, // 手势已经开始,此时已经被识别,但是这个过程中可能发生变化,手势操作尚未完成
UIGestureRecognizerStateChanged, // 手势状态发生转变
UIGestureRecognizerStateEnded, // 手势识别操作完成(此时已经松开手指)
UIGestureRecognizerStateCancelled, // 手势被取消,恢复到默认状态
UIGestureRecognizerStateFailed, // 手势识别失败,恢复到默认状态
UIGestureRecognizerStateRecognized // 手势识别完成,同UIGestureRecognizerStateEnded };
示例代码:设置手势
- 使用initWithTarget:action:初始化方法来创建一个手势识别器。initWithTarget:action:是所有手势识别器的基类初始化方法。
- 设置手势识别器对象实例的相关属性(delegate等)
- 使用addGestureRecognizer给UIView添加手势,addGestureRecognizer是所有UIView的基类方法。
//拖动手势
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizer:)];
[self addGestureRecognizer:panGesture];
-(void)panGestureRecognizer:(UIPanGestureRecognizer *)panGesture {
if (UIGestureRecognizerStateBegan == panGesture.state) {
// 拖动开始
}
else if (UIGestureRecognizerStateChanged == panGesture.state) {
// 拖动中,一般进行坐标设置
}
else (UIGestureRecognizerStateEnded == panGesture.state) {
// 拖动结束
}
}