请人做网站合同,免费制作app的软件下载,企业网络营销策略分析案例,长沙哪里有创建网站的公司事件传递
事件传递流程 发生触摸事件后#xff0c;系统会将该事件封装成UIEvent对象加入到一个由UIApplication管理的事件队列 UIApplication会从事件队列中取出最前面的事件#xff0c;并将事件分发下去以便处理#xff0c;通常#xff0c;先发送事件给应用程序的主窗口…事件传递
事件传递流程 发生触摸事件后系统会将该事件封装成UIEvent对象加入到一个由UIApplication管理的事件队列 UIApplication会从事件队列中取出最前面的事件并将事件分发下去以便处理通常先发送事件给应用程序的主窗口keyWindow。 主窗口会调用hitTest:withEvent: 方法沿着视图层次结构从上到下进行传递最后在视图层次结构中找到一个最合适的视图来处理触摸事件这也是整个事件处理过程的第一步 找到合适的视图控件后就会调用视图控件的touches方法touchesBegan、touchesMoved、touchedEnded来作具体的事件处理
触摸事件的传递是从父控件传递到子控件
也就是UIApplication-window-寻找处理事件最合适的view 触摸事件的传递是从父控件传递到子控件如果父控件不能接受触摸事件那么子控件就不可能接收到触摸事件 如何找到最合适的控件来处理事件 自己是否能接收触摸事件 触摸点是否在自己身上 从后往前遍历子控件重复前面的两个步骤 如果没有符合条件的子控件那么就自己最适合处理 UIView不接收触摸事件的三种情况 userInteractionEnabled NO隐藏 hidden YES; 透明:alpha 0.0 ~ 0.01; 通过pointInside:withEvent 方法判断触摸点是否在自己身上。返回NO则不在自己身上那就不再遍历子控件返回YES代表在自己身上那就继续遍历子控件从后往前遍历子控件重复前面两个步骤如果没有符合条件的子控件那么自己就是最适合处理的控件找到“最合适” 接收的控件后调用控件touchesBegantouchesMovedtouchedEnded的方法。 事件传递示例 点击了绿色的viewUIApplication - UIWindow - 白色 - 绿色 点击了蓝色的viewUIApplication - UIWindow - 白色 - 橙色 - 蓝色 点击了黄色的viewUIApplication - UIWindow - 白色 - 橙色 - 蓝色 - 黄色
寻找最合适的控件底层剖析
这里用到了两个重要的方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
hitTest:withEvent
只要事件一传递给一个控件,这个控件就会调用他自己的hitTestwithEvent方法
为了寻找并返回最合适的view(能够响应事件的那个最合适的view)
下面是其实现逻辑
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {// 1.判断下窗口能否接收事件if (self.userInteractionEnabled NO || self.hidden YES || self.alpha 0.01) return nil;// 2.判断下点在不在窗口上// 不在窗口上if ([self pointInside:point withEvent:event] NO) return nil;// 3.从后往前遍历子控件数组int count (int)self.subviews.count;for (int i count - 1; i 0; i--) {// 获取子控件UIView *childView self.subviews[i];// 坐标系的转换,把窗口上的点转换为子控件上的点// 把自己控件上的点转换成子控件上的点CGPoint childP [self convertPoint:point toView:childView];UIView *fitView [childView hitTest:childP withEvent:event];if (fitView) {// 如果能找到最合适的viewreturn fitView;}}// 4.没有找到更合适的view也就是没有比自己更合适的viewreturn self;} 首先判断下窗口能否接收事件 接着调用当前视图的pointInside:withEvent: 方法判断触摸点是否在当前视图内 若返回NO则hitTest:withEvent: 返回 nil。 若返回YES则向当前视图的所有子视图发送hitTest:withEvent: 消息所有子视图的遍历顺序是从最顶视图一直到最低层视图即从 subviews 数组的末尾向前遍历直到有子视图返回非空对象或者全部子视图遍历完毕。 若第一次有子视图返回非空对象则hitTest:withEvent:返回此对象处理结束。 若所有子视图都返回空则hitTest:withEvent:返回自身 不管这个控件能不能处理事件也不管触摸点在不在这个控件上事件都会先传递给这个控件随后再调用hitTest:withEvent:方法 如果hitTest:withEvent:方法中返回nil那么调用该方法的控件本身和其子控件都不是最合适的view也就是在自己身上没有找到更合适的view。那么最合适的view就是该控件的父控件。 pointInside:withEvent
判断点在不在当前view上方法调用者的坐标系上如果返回YES代表点在方法调用者的坐标系上;返回NO代表点不在方法调用者的坐标系上那么方法调用者也就不能处理事件。
事件响应
事件响应流程 如果找到最合适的控件来处理调用最合适的控件的touches…touchesBegan、touchesMoved、touchedEnded方法。 如果调用了[super touch…]就会将事件顺着响应者链往上传递传给上一个响应者接着上一个响应者就会调用touches…方法。 如果没有找到合适的控件来处理事件则将事件传回来窗口窗口不处理事件将事件传给 UIApplication。如果 UIApplication 不能处理事件则将其丢弃。 系统首先检查当前触摸到的视图是否响应事件如果响应事件传递结束否则转步骤2 系统检查当前触摸到的视图的控制器如果控制器响应则事件传递结束如果该视图没有控制器或者控制器不响应该事件则转步骤3 系统检查父视图再检查父视图的控制器以此类推 最后如果最顶层的视图/控制器也不响应则交给window
响应者
在iOS中不是任何对象都能处理事件只有继承了UIResponder的对象才能接收并处理事件称之为“响应者对象”。
UIApplication、UIViewController、UIView都继承自UIResponder因此它们都是响应者对象都能够接收并处理事件。
UIResponder提供了我们平时最常用的touchesBegan/touchesMoved/touchesEnded方法。此外还有如下几个属性比较重要 isFirstResponder:判断该View是否为第一响应者。 canBecomeFirstResponder:判断该View是否可以成为第一响应者。 becomeFirstResponder:使该View成为第一响应者。 resignFirstResponder:取消View的第一响应者。
第一响应者和最佳响应者 第一响应者 (First Responder): 第一响应者是指当前能够响应某个事件的第一个对象。通常情况下,当某个事件发生时,该事件首先被传递到第一响应者。第一响应者通常是用户当前正在交互的视图,比如用户正在编辑的 UITextField或者点击的 UIButton。 事件传递的目的就是为了让我们找到第一响应者 如何判断第一响应者 能够响应触摸事件触摸点在自己身上没有任何子视图或是所有子视图都不在触摸点上 最佳响应者 (Best Responder): 最佳响应者是指在响应者链上最适合处理某个事件的对象。当第一响应者无法完全处理某个事件时,该事件会沿着响应者链向上传递,直到找到最佳响应者。最佳响应者通常是能够最完整地处理该事件的对象,比如包含第一响应者的视图控制器。 一般来说,最佳响应者往往是包含当前第一响应者的视图控制器。 什么是上一个响应者
如果当前这个view是控制器的view那么控制器就是上一个响应者; 如果当前这个view不是控制器的view那么父控件就是上一个响应者。
响应者链条是什么
它是一种事件处理机制由多个响应者对象连接起来的层次结构使得事件可以沿着这些对象进行传递。利用响应者链条我们可以通过调用touches的super 方法让多个响应者同时响应该事件。
如何做到一个事件多个对象处理
因为系统默认做法是把事件上抛给父控件所以可以通过重写自己的touches方法和父控件的touches方法来达到一个事件多个对象处理的目的
iOS中的各种事件
iOS中的事件可以分为三种类型
触摸事件加速计事件远程控制事件 触摸事件UITouch
保存着跟手指相关的信息比如触摸的位置、时间、阶段。 当手指移动时系统会更新同一个UITouch对象使之能够一直保存该手指在的触摸位置。 当手指离开屏幕时系统会销毁相应的UITouch对象。
UITouch的常用属性和方法
property(nonatomic,readonly,retain) UIWindow *window;
//触摸产生时所处的窗口
property(nonatomic,readonly,retain) UIView *view;
//触摸产生时所处的视图
property(nonatomic,readonly) NSUInteger tapCount;
//短时间内点按屏幕的次数可以根据tapCount判断单击、双击或更多的点击
property(nonatomic,readonly) NSTimeInterval timestamp;
//记录了触摸事件产生或变化时的时间单位是秒
property(nonatomic,readonly) UITouchPhase phase;
//当前触摸事件所处的状态- (CGPoint)locationInView:(UIView *)view;
//返回值表示触摸在view上的位置这里返回的位置是针对view的坐标系的以view的左上角为原点(0, 0);调用时传入的view参数为nil的话返回的是触摸点在UIWindow的位置。
- (CGPoint)previousLocationInView:(UIView *)view;
//该方法记录了前一个触摸点的位置。
UIEvent
UIEvent称为事件对象记录事件产生的时刻和类型。 每产生一个事件就会产生一个UIEvent对象。 UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象UITouch。
property(nonatomic,readonly) UIEventType type;
property(nonatomic,readonly) UIEventSubtype subtype;
//事件类型
property(nonatomic,readonly) NSTimeInterval timestamp;
//事件产生的时间
触摸过程
一次完整的触摸过程通常会经历3个状态
触摸开始- (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
4个触摸事件处理方法中都有NSSet *touches和UIEvent *event两个参数。
当用户用手指触摸屏幕时会创建一个与手指相关联的UITouch对象。一根手指对应一个UITouch对象。
一次完整的触摸过程中只会产生一个事件对象4个触摸方法都是同一个event参数。如果两根手指同时触摸一个view那么view只会调用一次touchesBegan:withEvent:方法touches参数中装着2个UITouch对象。如果这两根手指一前一后分开触摸同一个view那么view会分别调用2次touchesBegan:withEvent:方法并且每次调用时的touches参数中只包含一个UITouch对象。根据touches中UITouch的个数可以判断出是单点触摸还是多点触摸。 touches中存放的都是UITouch对象 UIGestureRecognizer手势识别器
利用UIGestureRecognizer能轻松识别用户在某个view上面做的一些常见手势。 UIGestureRecognizer是一个抽象类定义了所有手势的基本行为使用它的子类才能处理具体的手势 UITapGestureRecognizer(敲击) UIPinchGestureRecognizer(捏合用于缩放) UIPanGestureRecognizer(拖拽) UISwipeGestureRecognizer(轻扫) UIRotationGestureRecognizer(旋转) UILongPressGestureRecognizer(长按)
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {// 没有触摸事件发生所有手势识别的默认状态UIGestureRecognizerStatePossible,// 一个手势已经开始但尚未改变或者完成时UIGestureRecognizerStateBegan,// 手势状态改变UIGestureRecognizerStateChanged,// 手势完成UIGestureRecognizerStateEnded,// 手势取消恢复至Possible状态UIGestureRecognizerStateCancelled, // 手势失败恢复至Possible状态UIGestureRecognizerStateFailed,// 识别到手势识别UIGestureRecognizerStateRecognized UIGestureRecognizerStateEnded
};
总结
传递链有系统向最上层view传递Application - window - root view - … - first view
响应连由最基础的view向系统传递first view - super view - … - view controller - window - Application - AppDelegate
穿透控件:
如果我们不想让某个视图响应事件只需要重载 PointInside:withEvent:方法让此方法返回NO就行了.
若是view上有view1view1上有view2点击view2view2自己响应点击view1view1不响应只有view响应也就是隔层传递