一、原理
1. UIResponder 类有一个名为 nextResponder 的属性,凡是 UIResponder 的对象或其子类对象都可以通过该属性组成一个 响应对象链
2. nextResponder 属性的指向
1)当某个 UIView 对象属于某个 UIViewController 对象时,则该 UIView 对象的 nextResponder 属性就指向该 UIViewController 对象;而该 UIViewController 对象的 nextResponder 属性指向该 UIView 对象的父视图
2)当某个 UIView 对象不属于任何 UIViewController 对象时,该 UIView 对象的 nextResponder 就指向其父视图
3)最顶层的父视图是 UIWindow 对象,而 UIWindow 对象指向 UIApplication 单例类
如图
3. 如果某个 UIResponder 对象没有处理传给它的事件,该对象就会将未处理的消息发送给自己的 nextResponder 对象;touchesBegin:withEvent: 此类消息就是这样实现的;如果直到最后的 UIApplication 对象也无法处理,系统就会抛弃该事件
二、实例
1. 详细代码
// LHSubView.h
#import <UIKit/UIKit.h>
@interface LHSubView : UIView
@end
// LHSubView.m
#import "LHSubView.h"
@implementation LHSubView
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"subView 响应");
// 手动向下传递
[[self nextResponder]touchesBegan:touches withEvent:event];
}
@end
// LHMainView.h
#import <UIKit/UIKit.h>
@interface LHMainView : UIView
@end
// LHMainView.m
@implementation LHMainView
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"mainView 响应");
// 手动向下传递
[[self nextResponder]touchesBegan:touches withEvent:event];
}
@end
// LHRootViewController.h
#import <UIKit/UIKit.h>
@interface LHRootViewController : UIViewController
@end
// LHRootViewController.m
#import "LHRootViewController.h"
#import "LHMainView.h"
#import "LHSubView.h"
@interface LHRootViewController ()
@property (nonatomic, strong) LHMainView * mainView;
@property (nonatomic, strong) LHSubView * subView;
@end
@implementation LHRootViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 创建主视图
_mainView = [[LHMainView alloc] initWithFrame:CGRectMake(50, 50, 200, 300)];
_mainView.backgroundColor = [UIColor orangeColor];
// 创建子视图
_subView = [[LHSubView alloc] initWithFrame:CGRectMake(30, 30, 100, 200)];
_subView.backgroundColor = [UIColor purpleColor];
[_mainView addSubview:_subView];
[self.view addSubview:_mainView];
self.view.backgroundColor = [UIColor blueColor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"LHRootViewController 响应");
// 手动向下传递
[[self nextResponder]touchesBegan:touches withEvent:event];
}
@end
// LHMyWindow.h
#import <UIKit/UIKit.h>
@interface LHMyWindow : UIWindow
@end
// LHMyWindow.m
@implementation LHMyWindow
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"MyWindow 响应");
// 手动向下传递
[[self nextResponder]touchesBegan:touches withEvent:event];
}
@end
// AppDelegate.h
#import "LHMyWindow.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) LHMyWindow *window;
@end
// AppDelegate.m
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[LHMyWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
self.window.rootViewController = [[LHRootViewController alloc] init];
self.window.backgroundColor = [UIColor whiteColor];
return YES;
}
2. 运行结果
3. 分析
1)当触摸紫色视图(LHSubview)时,因为 LHSubview 实现了 touchesBegin:withEvent: 方法,所以由 LHSubview 处理事件,并不会再向其 nextResponder 对象传递;如果 LHSubview 没有实现 touchesBegin:withEvent: 方法,就会向其 nextResponder 对象传递该方法,直至 UIApplication 类
2)当触摸橙色视图(LHMainView)时,因为触摸的是 LHMainView 对象,所以就从该对象开始查找事件方法,不会再向其 子视图搜索
3)因为代码中的 touchesBegin:withEvent: 方法中都添加了向其 nextResponder 对象发送 touchesBegin:withEvent: 方法的代码,所以,如果触摸紫色视图,则会从紫色视图开始至 UIApplication,中间的所有对象都会执行 touchesBegin:withEvent: 方法,结果如下