上一篇找到对应的touch View,找到touch View,
TSWindow
的SendEvent会解析成touchesBegan:withEvent:
,touchesMoved:withEvent:
,touchesEnded:withEvent:
,touchesCancelled:withEvent:
等事件。
事件解析部分对应表
| UIWindow(SendEvent:) | UITouchPhaseBegan | UITouchPhaseMoved |UITouchPhaseEnded|UITouchPhaseCancelled|
| :-------- | --------:| :------: |
| UIView | touchesBegan| touchesMoved |touchesEnded/touchesCancelled|touchesCancelled|
TSWindow
的SendEvent:
调用TouchBegin
系统并不是一一对应关系,UITouchPhaseEnded可能会调用touchesEnded
或者touchesCancelled
。具体怎么对应有个前置知识
.
前置知识
iOS中主要用到的触摸事件分为3种
- 使用
Target-Action
,此方法只适用于UIControl
的子类,例如UIButton
,UISlider
等- 使用手势,例如单击事件
UITapGestureRecognizer
.- 直接在
TouchesBegin:withEvents:
系列里边实现,例如自定义手势。
理解精要
-
Gesture
相对于Action
优先级较高 -
Gesture
与Action
从逻辑上说,与TouchesBegin
系列是两个- 层级的。无论有无Gesture
与Action
,TouchesBegin
系列都会调用。但是有Gesture
会影响TouchesBegin
系列。 - 所有的
TouchesBegin
系列Gesture
与Action
触发根本点是UIWIndow
的SendEvent
方法。 - 识别响应链获取需要响应的
Target
是在TouchBegins
阶段进行的 - 触发最终的响应实在
SendEvent
的UITouchPhaseEnded
阶段。 - 手势识别是有一个延时的,靠
UITouchPhaseBegan
与UITouchPhaseEnded
一个短暂的时间,在此中间能够正确识别就是一个手势。 - 只有
ViewController
的MainView
才会调用ViewController
的TouchesBegin
系列事件。 - 响应链跟View相关,所以在要自动调出键盘的
ViewController
里边,要在ViewDidAppare:
里边调用becomeFirstResponder
,而不能在ViewWillAppare:
. -
hit-testing
获取的UIView
,直接调用TouchesBegin:withEvents:
在此方法里,直接调用响应链.
第二步:响应链(The Responder Chain
)
什么是响应链?
响应链是一个类似于
链表
的结构,通过UIResponder
类的nextResponder
来维护,本质上只知道下一个响应者是谁。
响应链的顺序(别人的图)
enter image description here
原理
原理时序图
SequenceDiagram5.jpg结合Demo以及日志堆栈信息学习比较容易理解。
Apple Documents
的图
下边只是对
Apple Documents
的翻译
左边视图的执行顺序是:
-
initial view
试图处理事件或者消息,因为initial view
不是它的ViewController
的层级结构中最顶层的视图,如果它不能处理这个事件,则传递给它的SuperView
(不好翻译)。 - 它的
SuperView
试图处理事件,如果SuperView
不能处理这个事件,因为SuperView
还不是视图结构的最顶层,继续传递给SuperView
的SuperView
。 -
ViewController
层级中最顶级的View
试图去处理事件,如果topmost
视图也不能处理,则传递事件给Controller
. - 如果
ViewController
也管不了,交给Window
. -
Window
也不行,交给App
. -
App
也不行,扔了。
右边的略有不同,但套路一致
-
view
向上传递事件,直到ViewController
的topmost
View. -
topmost
View传给ViewController
. -
ViewController
又传递给它的topmost
View的superView
,1-3步循环,直到找到rootController
. -
rootController
传给Window
. -
Window
传给App
. -
App
也不行,扔了。
其实右图说的是
ViewController
套ViewController
.有一个ViewController
是容器类,容器类就是UIPAgeViewController
,UINAvigatorController
,UITabbarController
以及自定义的使用AddChildController
的各种。
举个例子
打断点跟用日志,表现方式不一致。原因在于触摸事件是时间相关的,所以在测试本工程请看日志,打断点会调用
TouchEnd
,日志则是TouchCancel
.或者在touchesbegin
打断点走Target-Action
不走Gesture
事件。
这是Demo中视图结构
TSEventDemo_xcodeproj.pngDemo类图
ClassDiagram1.jpg以单击事件为例
Target-Action
以及Gesture
Target-Action是适用于
UIControl
以及所有子类的,响应事件的一种方式
用法
TSTapView *tapView = [[TSTapView alloc] initWithFrame:CGRectMake(20, 120, 200, 300)];
tapView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:tapView];
[tapView addTarget:self action:@selector(_actionTap:) forControlEvents:UIControlEventTouchUpInside];
日志
- 点击
MainView
区域,MainView
无Target-Action
以及Gesture
事件。
2016-12-09 16:36:09.611 TSEventDemo[51488:2121613] -[TSAplication sendEvent:] Before 0
2016-12-09 16:36:09.612 TSEventDemo[51488:2121613] -[TSWindow sendEvent:] Before 0
2016-12-09 16:36:09.612 TSEventDemo[51488:2121613] -[TSMainView touchesBegan:withEvent:] Before
2016-12-09 16:36:09.613 TSEventDemo[51488:2121613] -[TSView touchesBegan:withEvent:] [name:(null)] Before
2016-12-09 16:36:09.613 TSEventDemo[51488:2121613] -[TSMainView nextResponder] Before
2016-12-09 16:36:09.613 TSEventDemo[51488:2121613] -[TSView nextResponder] [name:(null)] Before
2016-12-09 16:36:09.613 TSEventDemo[51488:2121613] -[TSView nextResponder] [name:(null)] After nextResponder:<TSTapViewController: 0x7f93cbf59500>
2016-12-09 16:36:09.613 TSEventDemo[51488:2121613] -[TSMainView nextResponder] After nextResponder:<TSTapViewController: 0x7f93cbf59500>
2016-12-09 16:36:09.613 TSEventDemo[51488:2121613] -[TSTapViewController touchesBegan:withEvent:] Before
2016-12-09 16:36:09.614 TSEventDemo[51488:2121613] -[TSTapViewController nextResponder] Before
2016-12-09 16:36:09.614 TSEventDemo[51488:2121613] -[TSTapViewController nextResponder] After nextResponder:<UIViewControllerWrapperView: 0x7f93cbeba600; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f93cbe97000>>
2016-12-09 16:36:09.614 TSEventDemo[51488:2121613] -[TSNavigationController touchesBegan:withEvent:] Before
2016-12-09 16:36:09.614 TSEventDemo[51488:2121613] -[TSNavigationController nextResponder] Before
2016-12-09 16:36:09.614 TSEventDemo[51488:2121613] -[TSNavigationController nextResponder] After nextResponder:<UIViewControllerWrapperView: 0x7f93cbd04a00; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f93cbd04d70>>
2016-12-09 16:36:09.615 TSEventDemo[51488:2121613] -[TSTabBarController touchesBegan:withEvent:] Before
2016-12-09 16:36:09.615 TSEventDemo[51488:2121613] -[TSTabBarController nextResponder] Before
2016-12-09 16:36:09.615 TSEventDemo[51488:2121613] -[TSTabBarController nextResponder] After nextResponder:<TSWindow: 0x7f93cbf3bc30; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7f93cbf3e5e0>; layer = <UIWindowLayer: 0x7f93cbf21ca0>>
2016-12-09 16:36:09.615 TSEventDemo[51488:2121613] -[TSWindow touchesBegan:withEvent:] Before
2016-12-09 16:36:09.616 TSEventDemo[51488:2121613] -[TSWindow nextResponder] Before
2016-12-09 16:36:09.616 TSEventDemo[51488:2121613] -[TSWindow nextResponder] After nextResponder:<TSAplication: 0x7f93cbe06930>
2016-12-09 16:36:09.616 TSEventDemo[51488:2121613] -[TSAplication touchesBegan:withEvent:] Before
2016-12-09 16:36:09.616 TSEventDemo[51488:2121613] -[TSAplication nextResponder] Before
2016-12-09 16:36:09.616 TSEventDemo[51488:2121613] -[TSAplication nextResponder] After nextResponder:<AppDelegate: 0x7f93cd101290>
2016-12-09 16:36:09.617 TSEventDemo[51488:2121613] -[TSAplication touchesBegan:withEvent:] After
2016-12-09 16:36:09.617 TSEventDemo[51488:2121613] -[TSWindow touchesBegan:withEvent:] After
2016-12-09 16:36:09.617 TSEventDemo[51488:2121613] -[TSTabBarController touchesBegan:withEvent:] After
2016-12-09 16:36:09.617 TSEventDemo[51488:2121613] -[TSNavigationController touchesBegan:withEvent:] After
2016-12-09 16:36:09.617 TSEventDemo[51488:2121613] -[TSTapViewController touchesBegan:withEvent:] After
2016-12-09 16:36:09.617 TSEventDemo[51488:2121613] -[TSView touchesBegan:withEvent:] [name:(null)] After
2016-12-09 16:36:09.618 TSEventDemo[51488:2121613] -[TSMainView touchesBegan:withEvent:] After
2016-12-09 16:36:09.618 TSEventDemo[51488:2121613] -[TSWindow sendEvent:] After 0
2016-12-09 16:36:09.618 TSEventDemo[51488:2121613] -[TSAplication sendEvent:] After 0
2016-12-09 16:36:09.684 TSEventDemo[51488:2121613] -[TSAplication sendEvent:] Before 3
2016-12-09 16:36:09.684 TSEventDemo[51488:2121613] -[TSWindow sendEvent:] Before 3
2016-12-09 16:36:09.685 TSEventDemo[51488:2121613] -[TSMainView touchesEnded:withEvent:] Before
2016-12-09 16:36:09.685 TSEventDemo[51488:2121613] -[TSView touchesEnded:withEvent:] [name:(null)] Before
2016-12-09 16:36:09.685 TSEventDemo[51488:2121613] -[TSMainView nextResponder] Before
2016-12-09 16:36:09.685 TSEventDemo[51488:2121613] -[TSView nextResponder] [name:(null)] Before
2016-12-09 16:36:09.685 TSEventDemo[51488:2121613] -[TSView nextResponder] [name:(null)] After nextResponder:<TSTapViewController: 0x7f93cbf59500>
2016-12-09 16:36:09.686 TSEventDemo[51488:2121613] -[TSMainView nextResponder] After nextResponder:<TSTapViewController: 0x7f93cbf59500>
2016-12-09 16:36:09.686 TSEventDemo[51488:2121613] -[TSTapViewController touchesEnded:withEvent:] Before
2016-12-09 16:36:09.686 TSEventDemo[51488:2121613] -[TSTapViewController nextResponder] Before
2016-12-09 16:36:09.687 TSEventDemo[51488:2121613] -[TSTapViewController nextResponder] After nextResponder:<UIViewControllerWrapperView: 0x7f93cbeba600; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f93cbe97000>>
2016-12-09 16:36:09.687 TSEventDemo[51488:2121613] -[TSNavigationController touchesEnded:withEvent:] Before
2016-12-09 16:36:09.687 TSEventDemo[51488:2121613] -[TSNavigationController nextResponder] Before
2016-12-09 16:36:09.688 TSEventDemo[51488:2121613] -[TSNavigationController nextResponder] After nextResponder:<UIViewControllerWrapperView: 0x7f93cbd04a00; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f93cbd04d70>>
2016-12-09 16:36:09.688 TSEventDemo[51488:2121613] -[TSTabBarController touchesEnded:withEvent:] Before
2016-12-09 16:36:09.688 TSEventDemo[51488:2121613] -[TSTabBarController nextResponder] Before
2016-12-09 16:36:09.689 TSEventDemo[51488:2121613] -[TSTabBarController nextResponder] After nextResponder:<TSWindow: 0x7f93cbf3bc30; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7f93cbf3e5e0>; layer = <UIWindowLayer: 0x7f93cbf21ca0>>
2016-12-09 16:36:09.689 TSEventDemo[51488:2121613] -[TSWindow touchesEnded:withEvent:] Before
2016-12-09 16:36:09.689 TSEventDemo[51488:2121613] -[TSWindow nextResponder] Before
2016-12-09 16:36:09.690 TSEventDemo[51488:2121613] -[TSWindow nextResponder] After nextResponder:<TSAplication: 0x7f93cbe06930>
2016-12-09 16:36:09.690 TSEventDemo[51488:2121613] -[TSAplication touchesEnded:withEvent:] Before
2016-12-09 16:36:09.690 TSEventDemo[51488:2121613] -[TSAplication nextResponder] Before
2016-12-09 16:36:09.690 TSEventDemo[51488:2121613] -[TSAplication nextResponder] After nextResponder:<AppDelegate: 0x7f93cd101290>
2016-12-09 16:36:09.691 TSEventDemo[51488:2121613] -[TSAplication touchesEnded:withEvent:] After
2016-12-09 16:36:09.691 TSEventDemo[51488:2121613] -[TSWindow touchesEnded:withEvent:] Before
2016-12-09 16:36:09.691 TSEventDemo[51488:2121613] -[TSTabBarController touchesEnded:withEvent:] After
2016-12-09 16:36:09.691 TSEventDemo[51488:2121613] -[TSNavigationController touchesEnded:withEvent:] After
2016-12-09 16:36:09.691 TSEventDemo[51488:2121613] -[TSTapViewController touchesEnded:withEvent:] After
2016-12-09 16:36:09.692 TSEventDemo[51488:2121613] -[TSView touchesEnded:withEvent:] [name:(null)] After
2016-12-09 16:36:09.692 TSEventDemo[51488:2121613] -[TSMainView touchesEnded:withEvent:] After
2016-12-09 16:36:09.692 TSEventDemo[51488:2121613] -[TSMainView nextResponder] Before
2016-12-09 16:36:09.692 TSEventDemo[51488:2121613] -[TSView nextResponder] [name:(null)] Before
2016-12-09 16:36:09.692 TSEventDemo[51488:2121613] -[TSView nextResponder] [name:(null)] After nextResponder:<TSTapViewController: 0x7f93cbf59500>
2016-12-09 16:36:09.693 TSEventDemo[51488:2121613] -[TSMainView nextResponder] After nextResponder:<TSTapViewController: 0x7f93cbf59500>
2016-12-09 16:36:09.693 TSEventDemo[51488:2121613] -[TSTapViewController nextResponder] Before
2016-12-09 16:36:09.693 TSEventDemo[51488:2121613] -[TSTapViewController nextResponder] After nextResponder:<UIViewControllerWrapperView: 0x7f93cbeba600; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f93cbe97000>>
2016-12-09 16:36:09.693 TSEventDemo[51488:2121613] -[TSNavigationController nextResponder] Before
2016-12-09 16:36:09.693 TSEventDemo[51488:2121613] -[TSNavigationController nextResponder] After nextResponder:<UIViewControllerWrapperView: 0x7f93cbd04a00; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f93cbd04d70>>
2016-12-09 16:36:09.694 TSEventDemo[51488:2121613] -[TSTabBarController nextResponder] Before
2016-12-09 16:36:09.694 TSEventDemo[51488:2121613] -[TSTabBarController nextResponder] After nextResponder:<TSWindow: 0x7f93cbf3bc30; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7f93cbf3e5e0>; layer = <UIWindowLayer: 0x7f93cbf21ca0>>
2016-12-09 16:36:09.694 TSEventDemo[51488:2121613] -[TSWindow nextResponder] Before
2016-12-09 16:36:09.694 TSEventDemo[51488:2121613] -[TSWindow nextResponder] After nextResponder:<TSAplication: 0x7f93cbe06930>
2016-12-09 16:36:09.694 TSEventDemo[51488:2121613] -[TSAplication nextResponder] Before
2016-12-09 16:36:09.695 TSEventDemo[51488:2121613] -[TSAplication nextResponder] After nextResponder:<AppDelegate: 0x7f93cd101290>
2016-12-09 16:36:09.695 TSEventDemo[51488:2121613] -[TSWindow sendEvent:] After 3
2016-12-09 16:36:09.695 TSEventDemo[51488:2121613] -[TSAplication sendEvent:] After 3
上边日志,严格按照原理
里提到的规则。这里不作分析
调试堆栈
这里
TSTapView
同时有Target-Action
以及Gesture
事件,分别给出堆栈信息。
同时注册Target-Action
以及Gesture
TSTapView *tapView = [[TSTapView alloc] initWithFrame:CGRectMake(20, 120, 200, 300)];
tapView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:tapView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_gestureTap:)];
[tapView addGestureRecognizer:tap];
[tapView addTarget:self action:@selector(_actionTap:) forControlEvents:UIControlEventTouchUpInside];
结果:
只有_gestureTap:
响应,_actionTap:
无响应。代表Gesture
优先Target-Action
响应,在_gestureTap:
响应之后,向hit-ttestting
获取的View发送了touchesCancelled:withEvent:
事件。
堆栈
thread #1: tid = 0x223729, 0x00000001000aa925 TSEventDemo`-[TSTapViewController _gestureTap:](self=0x00007faff9911810, _cmd="_gestureTap:", aTap=0x00007faff6c8aca0) + 53 at TSTapViewController.m:99, queue = 'com.apple.main-thread', stop reason = breakpoint 7.1
* frame #0: 0x00000001000aa925 TSEventDemo`-[TSTapViewController _gestureTap:](self=0x00007faff9911810, _cmd="_gestureTap:", aTap=0x00007faff6c8aca0) + 53 at TSTapViewController.m:99
frame #1: 0x0000000101ab8b28 UIKit`_UIGestureRecognizerSendTargetActions + 153
frame #2: 0x0000000101ab519a UIKit`_UIGestureRecognizerSendActions + 162
frame #3: 0x0000000101ab3197 UIKit`-[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 843
frame #4: 0x0000000101abb655 UIKit`___UIGestureRecognizerUpdate_block_invoke898 + 79
frame #5: 0x0000000101abb4f3 UIKit`_UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 342
frame #6: 0x0000000101aa8e75 UIKit`_UIGestureRecognizerUpdate + 2634
frame #7: 0x000000010163548e UIKit`-[UIWindow _sendGesturesForEvent:] + 1137
frame #8: 0x00000001016366c4 UIKit`-[UIWindow sendEvent:] + 849
frame #9: 0x00000001000a949d TSEventDemo`-[TSWindow sendEvent:](self=0x00007faff9a32ec0, _cmd="sendEvent:", event=0x00007faff6f0d2a0) + 861 at TSWindow.m:51
frame #10: 0x00000001015e1dc6 UIKit`-[UIApplication sendEvent:] + 263
frame #11: 0x00000001000a624d TSEventDemo`-[TSAplication sendEvent:](self=0x00007faff6f0c7c0, _cmd="sendEvent:", event=0x00007faff6f0d2a0) + 861 at TSAplication.m:42
frame #12: 0x00000001015bb553 UIKit`_UIApplicationHandleEventQueue + 6660
frame #13: 0x0000000100a68301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #14: 0x0000000100a5e22c CoreFoundation`__CFRunLoopDoSources0 + 556
frame #15: 0x0000000100a5d6e3 CoreFoundation`__CFRunLoopRun + 867
frame #16: 0x0000000100a5d0f8 CoreFoundation`CFRunLoopRunSpecific + 488
frame #17: 0x00000001057d8ad2 GraphicsServices`GSEventRunModal + 161
frame #18: 0x00000001015c0f09 UIKit`UIApplicationMain + 171
frame #19: 0x00000001000aaaf3 TSEventDemo`main(argc=1, argv=0x00007fff5fb5a580) + 115 at main.m:14
frame #20: 0x00000001039e492d libdyld.dylib`start + 1
注释掉Gesture
事件,只有Target-Action
* thread #1: tid = 0x205f8d, 0x000000010d509985 TSEventDemo`-[TSTapViewController _actionTap:](self=0x00007f93cbf59500, _cmd="_actionTap:", aTapView=0x00007f93cbee8f70) + 53 at TSTapViewController.m:105, queue = 'com.apple.main-thread', stop reason = breakpoint 5.1
* frame #0: 0x000000010d509985 TSEventDemo`-[TSTapViewController _actionTap:](self=0x00007f93cbf59500, _cmd="_actionTap:", aTapView=0x00007f93cbee8f70) + 53 at TSTapViewController.m:105
frame #1: 0x000000010ea21a8d UIKit`-[UIApplication sendAction:to:from:forEvent:] + 92
frame #2: 0x000000010eb94e67 UIKit`-[UIControl sendAction:to:forEvent:] + 67
frame #3: 0x000000010eb95143 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 327
frame #4: 0x000000010eb94263 UIKit`-[UIControl touchesEnded:withEvent:] + 601
frame #5: 0x000000010d50a714 TSEventDemo`-[TSTapView touchesEnded:withEvent:](self=0x00007f93cbee8f70, _cmd="touchesEnded:withEvent:", touches=1 element, event=0x00007f93cbe07440) + 148 at TSTapView.m:67
frame #6: 0x000000010ea9499f UIKit`-[UIWindow _sendTouchesForEvent:] + 835
frame #7: 0x000000010ea956d4 UIKit`-[UIWindow sendEvent:] + 865
frame #8: 0x000000010d50849d TSEventDemo`-[TSWindow sendEvent:](self=0x00007f93cbf3bc30, _cmd="sendEvent:", event=0x00007f93cbe07440) + 861 at TSWindow.m:51
frame #9: 0x000000010ea40dc6 UIKit`-[UIApplication sendEvent:] + 263
frame #10: 0x000000010d50524d TSEventDemo`-[TSAplication sendEvent:](self=0x00007f93cbe06930, _cmd="sendEvent:", event=0x00007f93cbe07440) + 861 at TSAplication.m:42
frame #11: 0x000000010ea1a553 UIKit`_UIApplicationHandleEventQueue + 6660
frame #12: 0x000000010dec7301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #13: 0x000000010debd22c CoreFoundation`__CFRunLoopDoSources0 + 556
frame #14: 0x000000010debc6e3 CoreFoundation`__CFRunLoopRun + 867
frame #15: 0x000000010debc0f8 CoreFoundation`CFRunLoopRunSpecific + 488
frame #16: 0x0000000112551ad2 GraphicsServices`GSEventRunModal + 161
frame #17: 0x000000010ea1ff09 UIKit`UIApplicationMain + 171
frame #18: 0x000000010d509af3 TSEventDemo`main(argc=1, argv=0x00007fff526fb580) + 115 at main.m:14
frame #19: 0x0000000110e4392d libdyld.dylib`start + 1
区别
Gesture
核心调用是_sendGesturesForEvent
,Target-Action
是_sendTouchesForEvent:
,而且明显_sendGesturesForEvent
会先于_sendTouchesForEvent:
调用。
模拟代码
UIWindow
的sendEvent
模拟代码
模拟的真实代码肯定还有很多处理,例如
ScrollView
等上的处理。
- (void)sendEvent:(UIEvent *)event
{
//如果是touch事件
if (event.type == UIEventTypeTouches) {
NSSet *touches = [event touchesForWindow:self];
NSMutableSet *gestureRecognizers = [NSMutableSet setWithCapacity:0];
for (UITouch *touch in touches) {
[gestureRecognizers addObjectsFromArray:touch.gestureRecognizers];
}
//先处理Gesture事件,如果正确识别则发送touchesCancelled:withEvent:
for (UIGestureRecognizer *recognizer in gestureRecognizers) {
[recognizer _recognizeTouches:touches withEvent:event];
}
for (UITouch *touch in touches) {
UIView *view = touch.view;
const UITouchPhase phase = touch.phase;
const _UITouchGesture gesture = [touch _gesture];
if (phase == UITouchPhaseBegan) {
[view touchesBegan:touches withEvent:event];
} else if (phase == UITouchPhaseMoved) {
[view touchesMoved:touches withEvent:event];
} else if (phase == UITouchPhaseEnded) {
[view touchesEnded:touches withEvent:event];
} else if (phase == UITouchPhaseCancelled) {
[view touchesCancelled:touches withEvent:event];
}
}
}
}
Target-Action
具体是什么做的
首先从
Target-Action
是UIControl
及其子类才有的功能,从Target-Action
堆栈以及日志能看出,其实Target-Action
事重写了TouchesBegin
系列事件实现的。
模拟代码
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
_touchInside = YES;
_tracking = [self beginTrackingWithTouch:touch withEvent:event];
self.highlighted = YES;
if (_tracking) {
UIControlEvents currentEvents = UIControlEventTouchDown;
if (touch.tapCount > 1) {
currentEvents |= UIControlEventTouchDownRepeat;
}
[self _sendActionsForControlEvents:currentEvents withEvent:event];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
const BOOL wasTouchInside = _touchInside;
_touchInside = [self pointInside:[touch locationInView:self] withEvent:event];
self.highlighted = _touchInside;
if (_tracking) {
_tracking = [self continueTrackingWithTouch:touch withEvent:event];
if (_tracking) {
UIControlEvents currentEvents = ((_touchInside)? UIControlEventTouchDragInside : UIControlEventTouchDragOutside);
if (!wasTouchInside && _touchInside) {
currentEvents |= UIControlEventTouchDragEnter;
} else if (wasTouchInside && !_touchInside) {
currentEvents |= UIControlEventTouchDragExit;
}
[self _sendActionsForControlEvents:currentEvents withEvent:event];
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
_touchInside = [self pointInside:[touch locationInView:self] withEvent:event];
self.highlighted = NO;
if (_tracking) {
[self endTrackingWithTouch:touch withEvent:event];
[self _sendActionsForControlEvents:((_touchInside)? UIControlEventTouchUpInside : UIControlEventTouchUpOutside) withEvent:event];
}
_tracking = NO;
_touchInside = NO;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
self.highlighted = NO;
if (_tracking) {
[self cancelTrackingWithEvent:event];
[self _sendActionsForControlEvents:UIControlEventTouchCancel withEvent:event];
}
_touchInside = NO;
_tracking = NO;
}
实际上addTarget:action:forControlEvents
是往数组里里添加一个键值对。在TouchesBegin
系列里进行处理的。
Demo
git
地址TSEventDemo
结束语
一些复杂手势,以及在ScrollView的事件没有做研究介绍。后续遇到问题研究了再写。
网友评论