iOS开发核心动画之事件处理

一. 事件

1. iOS中事件分为三种

  • 触摸

  • 加速计

  • 远程

2. 什么是响应者对象?

 

    继承了UIResponds的对象我们称它为响应者对象

 

    UIApplication、UIViewController、UIView都继承自UIResponder

 

    因此它们都是响应者对象,都能够接收并处理事件

    继承UIResponder称响应者对象

 

3. 事件调用方法

1> 触摸事件

```obj

  1. -(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
  2. -(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;
  3. -(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;
  4. -(void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event;

```

2> 加速计事件调用

  1. -(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent*)event;
  2. -(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent*)event;
  3. -(void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent*)event;

3> 远程控制事件

  1. -(void)remoteControlReceivedWithEvent:(UIEvent*)event;

 

4. 完整触摸过程

  1. 触摸开始:
  2. -(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
  3. 触摸移动:
  4. -(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
  5. 触摸结束:
  6. -(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
  7. 触摸取消(可能会经历,如来电时会调用):
  8. -(void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event

 

5. UIView拖拽

1> 自定义UIView,实现监听方法.

 

2> 确定在TouchMove方法当中进行操作,因为用户手指在视图上移动的时候才需要移动视图。

 

3> 获取当前手指的位置和上一个手指的位置.

 

4> 当前视图的位置 = 上一次视图的位置 + 手指的偏移量

 

 

 

 

关健代码实现:

 

  • 拿到UITouch就能获取当前点

 

  1. UITouch*touch =[touches anyObject];
  • 获取当前点

 

  1. CGPoint curP =[touch locationInView:self];
  • 获取上一个点    

  1. CGPoint preP =[touch previousLocationInView:self];
  • 获取手指x轴偏移量

 

  1. CGFloat offsetX = curP.x - preP.x;
  • 获取手指y轴偏移量

 

  1. CGFloat offsetY = curP.y - preP.y;
  • 移动当前view

 

  1. self.transform =CGAffineTransformTranslate(self.transform, offsetX, offsetY);

 

二. 事件的产生和传递

1. 事件的产生和传递

    当发生一个触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中.

 

    UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理.

 

    主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件

 

    触摸事件的传递是从父控件传递到子控件的.

 

    如果一个父控件不能接收事件,那么它里面的了子控件也不能够接收事件.

 

2. 一个控件什么情况下不能够接收事件

    . 不接收用户交互时不能够处理事件

 

      userInteractionEnabled = NO

 

    . 当一个控件隐藏的时候不能够接收事件

 

      Hidden = YES的时候

 

    . 当一个控件为透明白时候也不能够接收事件

 

 

 

    注意:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的

 

3. 如何寻找合适的View

1> 先判断自己是否能够接收触摸事件,如果能再继续往下判断,

 

2> 再判断触摸的当前点在不在自己的身上.

 

3> 如果在自己身上,它会从后往前遍历子控件,遍历出每一个子控件后,重复前面的两个步骤.

 

4> 如果没有符合条件的子控件,那么它自己就是最适合的View.

 

4. hitTest方法与PointInside方法

1> hitTest方法寻找合适的View,只要一个事件传递给控件时就会调用

  1. -(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event

2> PointInside方法判断当前点是否在此控件上(执行hitTest方法底层会调用此方法)

  1. -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event{
  2.     return YES;
  3. }

注:point必须得要跟当前View同一个坐标系.

 

5. hitText方法底层实现原理

  1. //作用:寻找最适合的View
  2. //什么时候调用:当事件传递给当前View时就会调用这个方法
  3. -(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event{
  4.  
  5.    //1.判断自己能否接收事件
  6.    if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <=0.01){
  7.        return nil;
  8.    }
  9.    //2.触摸点在不在自己身上
  10.    if([self pointInside:point withEvent:event]== NO){
  11.        return nil;
  12.    }
  13.    //3.从后往前遍历自己的子控件(重复前面的两个步骤)
  14.    
  15.    int count =(int)self.subviews.count;
  16.    //2,count i = 1 i = 0
  17.    for(int i = count -1; i >=0; i--){
  18.        
  19.        //取出子控件
  20.        UIView*childV = self.subviews[i];
  21.        //point必须得要跟childV相同的坐标系.
  22.        
  23.        //把point转换childV坐标系上面的点
  24.        CGPoint childP =[self convertPoint:point toView:childV];
  25.        UIView*fitView =[childV hitTest:childP withEvent:event];
  26.        if(fitView){
  27.            return fitView;
  28.        }
  29.    }
  30.    
  31.    //4.如果没有符合条件的子控件,那么就自己最适合处理
  32.    return self;
  33. }

 

三. 事件的响应和事件传递的完整过程

 

1. 事件响应

    用户点击屏幕后产生的一个触摸事件,经过一系列的传递过程后,会找到最合适的视图控件来处理这个事件,

 

    找到最合适的视图控件后,就会调用控件的touches方法来作具体的事件处理

 

    那这些touches方法的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理

 

 

 

 

什么是响应者链条?

 

    是由多个响应者对象连接起来的链条.

 

 

 

 

什么是响应者对象?

 

    继承了UIResponder对象我们称之为响应者对象,也就是能处理事件的对象

 

2. 事件传递的完整过程?

 

    在产生一个事件时,系统会将该事件加入到一个由UIApplication管理的事件队列中,

 

    UIApplication会从事件队列中取出最前面的事件,将它传递给先发送事件给应用程序的主窗口.

 

    主窗口会调用hitTest方法寻找最适合的视图控件,找到后就会调用视图控件的touches方法来做具体的事情.

 

    当调用touches方法,它的默认做法, 就会将事件顺着响应者链条往上传递,

 

    传递给上一个响应者,接着就会调用上一个响应者的touches方法

 

 

 

 

如何去寻找上一个响应者?

 

    1.如果当前的View是控制器的View,那么控制器就是上一个响应者.

 

    2.如果当前的View不是控制器的View,那么它的父控件就是上一个响应者.

 

    3.在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理

 

    4.如果window对象也不处理,则其将事件或消息传递给UIApplication对象

 

    5.如果UIApplication也不能处理该事件或消息,则将其丢弃

 

posted @ 2015-11-26 13:59  文刂Rn  阅读(572)  评论(0编辑  收藏  举报