概述
无论是在iOS还是在Android等以触屏为输入硬件的系统中,事件响应链都是很重要的,且设计的思想都是一样的。
一次触碰屏幕事件从外层向内层传递,从内层向外层响应。(隧道式传递,冒泡式响应)
iOS中事件传递AppDelegate -> UIWindow -> UIViewController -> 父UIView ->子UIView -> …
示例
我们自己新建自己的UIWindow,UIViewController,父UIView,子UIView用来演示响应顺序。涉及添加自己UIWindow请参看“iOS的UI-04-UIWindow”。
先看一下示例工程的目录
然后是各个文件的代码
需要仔细看各个情况下的log,来帮助理解事件传递和相应过程。
AppDelegate.h
#import <UIKit/UIKit.h>
//引入自定义window
#import "MYUIWindow.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate>
//window属性
@property(retain,nonatomic) MYUIWindow* window;
@end
AppDelegate.m
#import "AppDelegate.h"
//引入自定义的window和viewcontroller
#import "MYUIWindow.h"
#import "MYViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//初始化自定义window
self.window = [[MYUIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
//设置根视图控制器为我们自定义的视图控制器
self.window.rootViewController = [MYViewController new];
//给window设置个颜色,好区分个区域
self.window.backgroundColor = [UIColor blueColor];
//将自定义window添加并生效
[self.window makeKeyAndVisible];
return YES;
}
//点击屏幕回调
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//打印一下是否响应了事件,并打印下一个事件接受者
NSLog(@"AppDelegate 事件响应! next==%@",self.nextResponder);
//将事件传递给上级
[super touchesBegan:touches withEvent:event];
}
@end
MYUIWindow.m(头文件未做处理这里就不贴了)
#import "MYUIWindow.h"
@implementation MYUIWindow
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"MYUIWindow 事件响应! next==%@",self.nextResponder);
[super touchesBegan:touches withEvent:event];
}
@end
MYViewController.h
#import <UIKit/UIKit.h>
//引入俩个自定义view
#import "ParentView.h"
#import "ChildView.h"
NS_ASSUME_NONNULL_BEGIN
@interface MYViewController : UIViewController
{
//声明一下
ParentView* _pv;
ChildView* _cv;
}
@end
NS_ASSUME_NONNULL_END
MYViewController.m
#import "MYViewController.h"
@interface MYViewController ()
@end
@implementation MYViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//将两个自定义view添加到屏幕上
//为了区分个自的区域,设置view的大小和背景色
_pv = [ParentView new];
_pv.frame = CGRectMake(40, 40, 400, 500);
_pv.backgroundColor = [UIColor orangeColor];
_cv = [ChildView new];
_cv.frame = CGRectMake(60, 60, 200, 300);
_cv.backgroundColor = [UIColor redColor];
[_pv addSubview:_cv];
[self.view addSubview:_pv];
}
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"MYViewController 事件响应! next==%@",self.nextResponder);
[super touchesBegan:touches withEvent:event];
}
@end
ParentView.m(头文件未做处理这里就不贴了)
#import "ParentView.h"
@implementation ParentView
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"ParentView 事件响应! next==%@",self.nextResponder);
[super touchesBegan:touches withEvent:event];
}
@end
ChildView(头文件未做处理这里就不贴了)
#import "ChildView.h"
@implementation ChildView
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"ChildView 事件响应! next==%@",self.nextResponder);
[super touchesBegan:touches withEvent:event];
}
@end
注意:
仔细看代码中注释,很简单;
如果将各个类中的touchesBegan回调函数去掉,看会有什么样的结果;
将[super touchesBegan:touches withEvent:event]去掉会有什么结果;