iOS中的常见事件及其响应

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值