iOS 交互、手势与动画编程(上)| 青训营笔记

98 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第13天

iOS 交互、手势与动画编程(上)| 青训营笔记

对课程讲解内容进行重新编排,从最核心的事件机制开始,后面再实战举例。

iOS 事件响应机制

iOS 事件类型

  1. 触摸事件
  2. 运动事件(加速计)
  3. 远程操控事件(手柄)

iOS事件核心类:以触摸为例

UITouch:触摸对象,触摸时产生,用于记录单个手指的触摸事件

  1. 当用户触摸屏幕时,系统会创建一个UITouch集合(一根手指对应一个UITouch对象,该对象保存触摸事件的信息,如触摸的位置、时间、阶段等)
  2. 当用户移动手指时,系统会更新每个手指对应的UITouch对象保存的信息
  3. 当用户将手指离开屏幕时,系统会销毁相应的UITouch对象

UIEvent:触摸事件,用于记录一个完整的触摸过程

  1. 记录产生的时刻和类型
  2. 记录当前多点触摸序列相对应的所有触摸对象
  3. 提供与特定视图或窗口相关联的触摸对象

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;

事件传递和响应链

事件传递

  1. 发生触摸事件后,系统将事件加入到 UIApplication*管理的事件队列中
  2. UIApplication从事件队列中取出最前面的事件,并将其分发下去处理,通常先发送事件给应用程序的主窗口keyWindow
  3. keyWindow 会在视图层次结构中, 找到一个最适合的视图第一响应者First responder来处理触摸事件(命中测试hitTest:withEvent)
  4. hitTest:withEvent判断响应者
    1. 判断自身是否能够响应:userlnteractionEnabled、hidden、alpha
    2. 判断触摸点是否在自己frame范围内 (pointinside : withEvent )
    3. 由上到下遍历自己的子视图递归调用该方法,判断是否有返回view
    4. 如果子视图都没有能力响应,返回自己

响应链: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 };

示例代码:设置手势

  1. 使用initWithTarget:action:初始化方法来创建一个手势识别器。initWithTarget:action:是所有手势识别器的基类初始化方法。
  2. 设置手势识别器对象实例的相关属性(delegate等)
  3. 使用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) {
    // 拖动结束
    }
}