安徽工程建设信息网新网站,网站建设费记到什么科目,网站过度优化首页被k,销售易crm收费标准响应者链
响应者链是由一系列链接在一起的响应者#xff08;UIResponser之类#xff1a;UIApplication#xff0c;UIViewController#xff0c;UIView#xff09;注组成的。一般情况下#xff0c;一条响应链开始于第一响应者#xff0c;结束于application对象。如果一个…响应者链
响应者链是由一系列链接在一起的响应者UIResponser之类UIApplicationUIViewControllerUIView注组成的。一般情况下一条响应链开始于第一响应者结束于application对象。如果一个响应者不能处理事件会将事件沿着响应者链传到下一个响应者
响应者对象
在响应者链中每个响应者对象都可以处理事件也可以选择将事件传递给下一个响应者对象进行处理或者直接丢弃事件。响应者链中的每个响应者对象都可以重写几个方法来处理事件这些方法包括touchesBegan:withEvent:、touchesMoved:withEvent:、touchesEnded:withEvent:等等。
响应者对象都实现了UIResponder协议这里的实现UIResponder协议指UIApplication、UIViewController、UIView 都继承于 UIResponder。
常见的响应者对象
UIView是iOS中最基本的用户界面元素可以接收用户的触摸事件并进行相关的处理。UIViewController作为MVC模式中的控制器可以响应用户的触摸事件同时还可以管理一个或多个视图控制器。UIWindow是整个应用程序的窗口它包含了一个或多个视图并且是接收和处理触摸事件的最高层响应者对象。UIGestureRecognizer是iOS中专门用来处理手势事件的响应者对象包括UITapGestureRecognizer、UIPanGestureRecognizer、UILongPressGestureRecognizer等等。UIScrollView是一个可以滚动的视图控件它可以接收用户的触摸事件并在触摸拖动时进行滚动。UITableView是iOS中常用的列表视图控件它可以显示大量的数据并且可以处理用户的滑动、点击等事件
响应者事件
iOS 中的事件可分为触摸事件multitouch events、加速计事件accelerometer events包括摇晃、倾斜、加速等设备运动、远程控制事件remote control events可以来自于耳机、锁屏界面和控制中心等例如暂停音乐、切换歌曲等。
基本元素的了解
系统是怎么响应用户的触屏事件这里有与用户事件相关的类它们分别是UITouch UIEvent和UIResponder
UIResponder事件响应者
UIResponder是iOS中的一个基类定义了一些接口用于处理触摸事件和键盘事件。所有能够接受并处理事件的对象都继承于UIResponder
UIResponder内部提供了以下方法来处理事件
// 一根或者多根手指开始触摸view系统会自动调用view的下面方法
- (void)touchesBegan:(NSSetUITouch * *)touches withEvent:(nullable UIEvent *)event;
// 一根或者多根手指在view上移动系统会自动调用view的下面方法随着手指的移动会持续调用该方法
- (void)touchesMoved:(NSSetUITouch * *)touches withEvent:(nullable UIEvent *)event;
// 一根或者多根手指离开view系统会自动调用view的下面方法
- (void)touchesEnded:(NSSetUITouch * *)touches withEvent:(nullable UIEvent *)event;
// 触摸结束前某个系统事件(例如电话呼入)会打断触摸过程系统会自动调用view的下面方法[可选]
- (void)touchesCancelled:(nullable NSSetUITouch * *)touches withEvent:(nullable UIEvent *)event;通过重写UIresponder中定义的方法开发者可以自己类中处理用户事件并做出相应的事件
UITouch触摸
UITouch是触摸对象一个手指一次触摸屏幕就会生成一个UITouch对象若两个手指先后触摸同一个位置第一次触摸时生成一个UITouch对象第二次触摸更新UITouch对象的tapCount属性值由1变成2如果两个手指一前一后触摸的位置不同将会生成两个UITouch对象两者没有联系。每个UITouch对象会记录触摸的一些记录包括触摸时间、位置、阶段、所处的视图和窗口等信息。 当手指移动时系统会更新同一个UITouch对象使之能够保存该手指的触摸位置当手指离开屏幕上时系统会销毁响应的UITouch对象UITouch对象会在触摸事件的过程中不断更新直到触摸事件结束。在触摸事件的过程中系统会不断向响应链的响应者发生事件并将触摸事件封装成UIEvent对象进行传递。当触摸事件结束时系统就会销毁相应的UITouch对象
UITouch的属性
// 记录了触摸事件产生或变化时的时间单位是秒 The relative time at which the acceleration event occurred(read-only)
property(nonatomic,readonly) NSTimeInterval timestamp;
// 当前触摸事件所处的状态
property(nonatomic,readonly) UITouchPhase phase;
// touch down within a certain point within a certain amount of timen 短时间内点按屏幕的次数可以根据tapCount判断单击、双击或更多的点击
property(nonatomic,readonly) NSUInteger tapCount;
property(nonatomic,readonly) UITouchType type NS_AVAILABLE_IOS(9_0);
// 触摸产生时所处的窗口
property(nullable,nonatomic,readonly, strong) UIWindow *window;
// 触摸产生时所处的视图
property(nullable,nonatomic,readonly, strong) UIView *view;
// The gesture-recognizer objects currently attached to the view.
property(nullable,nonatomic,readonly,copy) NSArray UIGestureRecognizer * *gestureRecognizersUITouch方法
/*返回值表示触摸在view上的位置
这里返回的位置是针对view的坐标系的以view的左上角为原点(0, 0)
调用时传入的view参数为nil的话返回的是触摸点在UIWindow的位置*/
- (CGPoint)locationInView:(nullable UIView *)view;
// 该方法记录了前一个触摸点的位置
- (CGPoint)previousLocationInView:(nullable UIView *)view;// Use these methods to gain additional precision that may be available from touches.
// Do not use precise locations for hit testing. A touch may hit test inside a view, yet have a precise location that lies just outside.//获取指定视图上的精确触摸位置该方法会考虑到多点触控时不同触点之间的偏移。
- (CGPoint)preciseLocationInView:(nullable UIView *)view API_AVAILABLE(ios(9.1));
// 获取指定视图上上一次触摸的精确位置。
- (CGPoint)precisePreviousLocationInView:(nullable UIView *)view API_AVAILABLE(ios(9.1));UIEvent事件
UIEvent 是 iOS 中用于表示触摸事件的类一个 UIEvent 对象包含了所有与触摸事件相关的信息比如触摸的位置、时间、阶段以及多点触控时不同触点之间的状态等等。UIEvent 对象是由系统自动创建和管理的通常情况下不需要手动创建。每产生一个事件就会产生一个 UIEvent 对象UIEvent 称为事件对象。
事件类型属性
//事件类型枚举值包括触摸、运动、遥控等。
property(nonatomic,readonly) UIEventType type NS_AVAILABLE_IOS(3_0);// 事件子类型对于触摸事件其子类型包括touch down、touch move、touch up等。
property(nonatomic,readonly) UIEventSubtype subtype NS_AVAILABLE_IOS(3_0);产生时间的事件属性
事件发生的时间戳单位为秒。
property(nonatomic,readonly) NSTimeInterval timestamp;事件的传递和响应 步骤一寻找目标在iOS的视图层次结构中找到事件的最终接受者步骤二事件响应·基于iOS响应者链处理触摸事件
事件的传递寻找事件的第一响应者Hit_Testing)
当一个事件发生时事件会从父控件传给子控件 也就是说由
硬件 - 系统 - UIApplication - UIWindow - SuperView - SubView
以上就是事件的传递也就是寻找第一响应者的过程。
符合第一响应者的条件包括
touch事件的位置在响应者区域内 pointInside:withEvent: YES响应者 self.hidden ! NO响应者 self.alpha 0.01响应者 self.userInteractionEnabled YES遍历 subview 时是从上往下顺序遍历的即 view.subviews 的 lastObject 到 firstObject 的顺序找到合适的响应者view即停止遍历.
第一响应者对于接收到的事件的三种操作
不拦截默认操作。事件会自动沿着默认的响应者链往下传递拦截不再往下分发事件。重写 touchesBegan:withEvent: 进行事件处理不调用父类的 touchesBegan:withEvent:拦截继续往下分发事件。重写 touchesBegan:withEvent: 进行事件处理同时调用父类的 touchesBegan:withEvent: 将事件往下传递
事件的响应一旦事件的第一响应者确定了这个事件的响应链就确定了
下图是官网对于响应者链的实例展示 每个响应者对象UIResponder对象都有一个nextResponder方法用于获取响应者链中当前对象的下一个响应者。
图中虚线箭头是指若该UIView是作为UIViewController根视图存在的则其nextResponder为UIViewController对象若是直接add在UIWindow上的则其nextResponder为UIWindow对象。
若触摸发生在UITextField上则事件的传递顺序是
UITextField —— UIView —— UIView —— UIViewController —— UIWindow —— UIApplication —— UIApplicationDelegation
虽然两个传递过程都设计到父子控件的传递但它们的传递顺序和目的不同触摸事件的传递过程主要是为了找到最合适的空间来处理事件而响应者链传递过程是为了让控件的响应者对象能够逐级处理事件。
事件的生命周期
手指触摸屏幕的一刻系统会生成一个触摸事件。经过IPC进程间通信事件最终被传递给了合适的应用。
一系统响应阶段
屏幕感应到触碰后将事件交给IOKit处理IOKit是监测硬件的框架。IOKit将触摸事件封装成一个IOHIDEvent对象并通过mach port传递给SpringBoard进程。 mach port是进程端口各个进程之间通过它进行通信 SpringBoard.app是一个系统进程可以理解为桌面系统可以统一管理和分发系统接收到的触摸事件 SpringBoard.app进程收到触摸事件触发主线程RunLoop的source1事件源的回调。SpringBoard.app会根据当前桌面的状态判断应该由谁响应此次触摸事件。如果没有APP在运行则由SpringBoard处理该事件如果有APP在运行则由APP处理该事件
二APP响应阶段
APP进程的mach port接收到SpringBoard进程传递来的触摸事件主线程的RunLoop被唤醒触发source1回调source1回调触发了一个source0回调将接收到的IOHIDEvent对象封装成UIEvent对象source0回调内部将触摸事件添加到UIApplication对象的事件队列中。事件出队列后UIApplication开始寻找一个最佳响应者的过程这个过程又称为hit-testing具体细节在第二个主题寻找最佳响应者中阐述找到最佳响应者后事件就在响应链中传递和响应这里涉及到“事件的响应和响应链中的传递”经过上述流程触摸事件要么被某个响应对象捕获后释放要么没有找到能响应的对象被释放
总结触摸事件从触屏产生后有IOKit将触摸事件传递给SpringBoard进程再由SpingBoard分发给当前前台APP处理触发事件响应者链事件。
完整的触摸过程
一个完整的触摸事件流程通常包括以下几个步骤
手指触摸到屏幕系统会创建一个与手指相关联的 UITouch 对象并将其加入到系统中的事件队列中。系统会将该事件发送给当前 UIWindow 对象即调用 UIWindow 对象的 touchesBegan(_:with:) 方法并将该事件传递给子视图。从根视图开始系统会通过递归调用 hitTest(_:with:) 方法寻找响应该事件的视图。在每个视图中系统都会调用 point(inside:with:) 方法判断该视图是否包含该事件的触摸点。一旦找到了响应该事件的视图系统会将该事件发送给该视图即调用该视图的 touchesBegan(:with:) 方法。在该视图的 touchesBegan(:with:) 方法中开发者可以对该事件做出相应的处理比如更改视图的状态、更新视图的内容等。如果该事件需要传递给其它视图进行处理开发者可以手动调用 next 方法将该事件传递给下一个响应者。当手指离开屏幕时系统会将一个 touch 对象的 phase 属性设置为 .ended并将该 touch 对象从事件队列中移除。当前的 UIWindow 对象会将该事件发送给响应者链中的下一个响应者。如果没有下一个响应者则该事件的响应过程结束。
总结
当触摸事件发生后系统会自动生成一个UIEvent对象记录事件发生的事件和类型然后系统会把UIEvent事件加入到一个由UIApplocation管理的事件队列中然后UIApplication会讲事件分发给UIWindow主窗口会在视图层次结构中找到一个合适的响应者对象来处理触摸事件。不断递归调用hitTest方法来找到第一响应者如果第一响应者无法响应事件那么会按照响应者链往上传递也就是传递给自己的父视图一直传递直到UIApplication如果都无法响应事件就会被丢弃