iOS事件

概述

iOS中事件有触摸事件、加速计事件、远程控制事件,下面以触摸事件为例研究下iOS事件相关的内容


iOS事件分类

UIResponsder

iOS中继承了UIResponsder的对象才能够响应事件,如UIViewControllerUIViewUIApplication
UIResponsder能够响应事件的原因是:提供了几个方法来处理事件

//触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;//手指触摸事件开始时调用该方法
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;//手指在屏幕上移动时调用该方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)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;

备注:

  1. 当多个手指同时触摸屏幕时,只会调用一次touchesBegan:withEvent:方法,touches中包含多个UITouch对象,分别对应着触摸屏幕的手指
  2. 如果是UIViewController的事件,在UIViewController中重写上面用到的方法即可;如果是UIView的事件,需要在子类中重写上面用到的方法

实例:触摸屏幕,移动屏幕上的某个UIButton

UIView的子类中重写touchesMoved: withEvent:方法

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];//当前点的位置
    CGPoint previousPoint = [touch previousLocationInView:self];//上一个点的位置
    CGFloat xPoint = point.x - previousPoint.x;
    CGFloat yPoint = point.y - previousPoint.y;
    NSLog(@"point:%@;previousPoint:%@;xPoint:%f;yPoint:%f",NSStringFromCGPoint(point), NSStringFromCGPoint(previousPoint), xPoint, yPoint);
    CGPoint centerPoint = self.btn.center;
    centerPoint = CGPointMake(centerPoint.x + xPoint, centerPoint.y + yPoint);
    self.btn.center = centerPoint;
}

iOS 事件处理过程

iOS事件分为事件传递、事件响应两个过程。

事件的产生

发生触摸事件后,系统会将事件加入到由UIApplication管理的队列(先进先出FIFO),然后将队列最前面的事件分发下去:UIApplication->keyWindow->视图层次结构,找到合适的视图控件后,就会调用对应控件的事件方法(touchesBegan: withEvent:等)来处理对应的事件。

事件的传递

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

  • 寻找响应事件的控件步骤
    1. 首先判断keyWindow是否能响应事件
    2. 触摸点是否在自己身上
    3. 从后往前遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)
    4. 如果没有符合条件的子控件,那就认为自己可以处理
  • UIView不能响应事件的三种情况
  1. 不允许交互userInteractionEnabled = NO
  2. 隐藏的控件不能接收事件
  3. 透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。

事件传递实例

注意:如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件

事件传递实例

查找符合条件的控件原理

主要是通过以下两个控件实现查找

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;//返回nil,表明当前view以及子view没有能够响应事件的;如果不为nil,则表明当前view中有能响应事件的
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;//返回YES,表明触摸点在当前view中

通过调用hitTest:withEvent:可以判断是否有能够响应事件的控件,具体步骤为:
产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回合适的view->[子控件 hitTest:withEvent:]->返回合适的view
不过子控件是否能够响应事件,父控件都会把事件传递给子控件,如果子控件不能响应事件,则父控件响应事件

实例:view中的button响应事件

参考iOS超出父视图后点击事件不响应,文中想要view中的button响应点击事件,因此重写了hitTest:withEvent:方法

响应者链

在iOS程序中无论是最后面的UIWindow还是最前面的某个按钮,它们的摆放是有前后关系的,一个控件可以放到另一个控件上面或下面,那么用户点击某个控件时是触发上面的控件还是下面的控件呢,这种先后关系构成一个链条就叫“响应者链”。

事件响应过程
  • 如果当前控件无法响应事件,就将事件按照视图层级结构(最上层是根视图)向上传递。如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,事件就传递给它的父视图
  • 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
  • 如果window对象也不处理,则其将事件或消息传递给UIApplication对象
  • 如果UIApplication也不能处理该事件或消息,则将其丢弃

总结

  1. 触摸屏幕产生触摸事件后,触摸事件会被添加到由UIApplication管理的事件队列中
  2. UIApplication会从事件队列中取出最前面的事件,把事件传递给keyWindow
  3. keyWindow会在视图层次结构中找到一个最合适的视图来处理触摸事件
  4. 最合适的view会调用自己的touches方法处理事件,如果不能处理事件,就将事件沿着响应者链向上抛

问题与解决方案

  1. 向 WKWebView 添加 UITapGestureRecognizer 点击识别,会发现不起作用,怎样解决?
    解决:实现 gesture 的 delegate,允许两个 gesture 同时识别
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }

附图

UIResponder

UIKit 结构图

参考

  1. iOS事件传递->处理->响应
  2. iOS超出父视图后点击事件不响应
  3. iOS触摸事件全家桶
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 用户以多种方式操纵他们的iOS设备,例如触摸屏幕或摇动设备。 iOS会解释用户何时以及如何操作硬件并将此信息传递到...
    坤坤同学阅读 3,922评论 7 19
  • 本次笔记主要是整理一下关于 iOS 中关于事件传递和响应机制,参考了一些其他资料加上自己的理解。 事件 Event...
    varlarzh阅读 305评论 0 2
  • 事件传递:响应者链 当你设计一个app的时候,你很可能需要你的app能够动态响应某些事件。比如,触摸可以发生在屏幕...
    hjfrun阅读 980评论 1 5
  • 本篇主要讲解iOS事件传递的整个过程,大部分内容翻译自Apple Developer Guide,原文链接 当一个...
    Little_Mango阅读 1,236评论 4 10
  • 本文主要参考了 VV木公子(简书作者)的 史上最详细的iOS之事件的传递和响应机制我按照自己的理解做了排版和一些表...
    hi_xgb阅读 2,566评论 4 28