iOS中的常见事件及其响应

来源:互联网 发布:天下三男鬼墨捏脸数据 编辑:程序博客网 时间:2024/06/09 16:01

iOS中的事件

在使用app过程中,会产生各种各样的事件
可以分为三大类
这里写图片描述

响应者对象

  • iOS中只有继承了UIResponder才能接收并处理事件,称为响应者对象
  • UIApplication、UIViewController、UIView都继承UIResponder。所以他们都是响应者对象,都能接收并处理事件
  • UIResponder内部提供一些方法
触摸事件

注:如果处理UIView的触摸事件,必须要自定义UIView的子类,在子类中重写以下四个方法

//当手指开始触摸View时,系统会自动调用- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event//当手指在view上移动时,系统自动调用 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event //当手指在view上离开时,系统自动调用 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event //结束触摸时,某个系统事件(例如电话呼入)会打断触摸过程,,系统自动调用 - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
加速事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
远程控制事件
 - (void)remoteControlReceivedWithEvent:(UIEvent *)event

UIView的触摸事件处理

关于UITouch

  • 当用户用一根手指触摸屏幕时,系统会创建一个与手指相关联的UITouche对象
  • 一个手指对应一个UITouch对象(如果两个手指同时触摸一个view,那么view只会调用一次toucheBegan方法,touches包含两个UITouch对象)

  • UITouch的作用:

    • 保存着和手指相关的信息,比如触摸的位置,时间,阶段
    • 当手指移动时,系统会更新同一个UITouch对象,使之能够一直保持该手指在触摸的位置
    • 当手指离开屏幕时,系统会销毁相应的UITouch对象
      注: iphone开发,要避免使用双击事件
  • UITouch的常用方法

返回值表示触摸在View上的位置返回的位置是针对view的坐标(左上角为原点)若传入参数的view是nil的话,返回的值表示在UIWindow的位置- (CGPoint)locationInView:(nullable UIView *)view;
返回前一个触摸点的位置- (CGPoint)previousLocationInView:(nullable UIView *)view;

关于实现UIView拖拽的代码

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    //获取对象    UITouch *touch = [touches anyObject];    //当前手指的位置    CGPoint currentP = [touch locationInView:self];    //之前手指的位置    CGPoint previousP = [touch previousLocationInView:self];    //计算偏移量    CGFloat offsetX = currentP.x - previousP.x;    CGFloat offsetY = currentP.y - previousP.y;    self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);}

关于UIEvent

  • 每产生一个事件,就会产生一个UIEvent对象
  • UIEvent:称为事件对象,记录产生的时刻和类型
typedef NS_ENUM(NSInteger, UIEventType) {    UIEventTypeTouches,//触摸    UIEventTypeMotion,//加速器    UIEventTypeRemoteControl,//远程    UIEventTypePresses,3D touch};

事件的产生和传递

事件的产生

  • 发生触摸事件后,系统就会将该事件加入到一个由UIApplication管理的事件队列中
  • UIApplication会从事件队列中找到最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)
  • 主窗口会在视图层次结构中找到一个最适合的视图来处理触摸事件,这也是整个事件处理过程的第一步
  • 找到最适合的视图控件后,就会调用视图控件的touches方法来做具体的事件处理
UIApplicaton -> UIWindow -> UIViewControleler -> UIView -> subView

事件的传递

  • 触摸事件的传递是从父控件传递到子控件
  • 如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件
  • UIView不能接收事件的三种情况
    • 不接收用户交互
      userInteractionEnabled = NO
    • 隐藏
      hidden = YES
    • 透明
      alpha = 0.0 ~0.01
      注:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸时间的

找到最适合的View

  • 当前View能否接收触摸事件
  • 触摸点是否在当前View上
    子视图数组从后往前(从视图的顶部往底部)遍历子控件,重复这俩个步骤

    这里写图片描述

在查找最合适的view的两个最重要的方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

关于hitTest:withEvent:

当事件传递给一个控件,这个控件就会调用自己的hitTest:withEvent:方法,用于寻找并返回最合适的view, 它不管这个控件能不能处理事件也不管点是否在view上,事件都会先传给这view再调用这个view的hitTest方法。不管点击哪里,最合适的view都是hitTest返回的那个view。

注:
1、重写window的hitTest:withEvent:方法return nil,谁都不能处理事件,窗口也不能处理
2、控制器的view的hitTest:withEvent:方法,return nil或者window的hitTest:withEvent:方法,return self,只能由窗口处理事件。
3、调用当前hitTest:withEvent:方法的view不是合适的view,子控件也不是合适的view。如果同级的兄弟控件也没有合适的view,那么最合适的view就是父控件

pointInside:withEvent

判断点在不在当前view上(方法调用者的坐标系上)如果返回YES,代表点在方法调用者的坐标系上;返回NO代表点不在方法调用者的坐标系上,那么方法调用者也就不能处理事件。

最合适的view代码实现

UIApplication -> keyWindow ->view -> …

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{    //判断当前控件能否接收事件    if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha == 0) {        return nil;    }    //判断点在不在当前的控件    if ([self pointInside:point withEvent:event] == NO) {        return nil;    }    NSInteger count = self.subviews.count;    for (NSInteger i = count - 1; i >= 0; i --) {        UIView *childView = self.subviews[i];        //把当前控件的坐标系改为控件上的坐标系        CGPoint childp =[self convertPoint:point toView:childView];        UIView *fifView = [childView hitTest:childp withEvent:event];        if (fifView) {            //寻找最适合的View            return fifView;        }    }    //当前的就是最适合的    return self;}
原创粉丝点击