在cocochina上看到一篇文章《巧用UIResponder进行事件传递》,发现了UIResonder类的nextResponder属性。由于原文涉及的内容比较多,所以我自己专门将该知识点进行了一下整理。这是一个很有用的属性,对于UIView,nextResponder就是其SuperView或者ViewController,这样在做事件传递的时候可以不用设置delegate或block。
看一个例子前,我先提一下2个知识点:
- 事件响应链:当用户点击一个UIView时,系统会产生一个事件,并将其放入UIApplication的事件队列中。然后该事件会顺着这条链传递到用户点击的那个UIView:UIApplication->UIWindow->RootView->...->Subview。然后开始处理这个事件,若Subview不处理,事件将会传递给其�视图控制器,若没有控制器则传给其superView,最后传给UIWindow,UIApplication。若UIApplication还是没处理则将事件传给nil。
- UIResponder具有nextResponder属性,也就是其SuperView或是UIViewConterller等。UIView是UIResponder的子类,所以UIView及其子类都能使用此属性。
好了,现在可以看这个应用实例:点击cell上的按钮,将事件传给ViewController,显示点击的cell的index。之前没用nextResponder属性,把事件从cell上的按钮传到ViewController需要将VIewController作为参数传入cell或者设置代理与block。
1.首先为UIResponder创建一个分类,
#import<UIKit/UIKit.h>
@interface UIResponder (Router)
-(void)routerEvent:(id)info;
@end
#import "UIResponder+Router.h"
@implementation UIResponder (Router)
-(void)routerEvent:(id)info{
[self.nextResponder routerEvent:info];
}
@end ```
2.然后在ViewController中加入一个UITableview和UILable;
```Object-C
#import "ViewController.h"
#import "TableViewCell.h"
#import "UIResponder+Router.h"
@interface ViewController ()<UITableViewDataSource>
@property(strong, nonatomic)UILabel *mLbl;
@property(strong, nonatomic)UITableView *mTableView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CGFloat w0 = self.view.bounds.size.width;
CGFloat h0 = 80.;
_mLbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, w0, h0)];
_mLbl.backgroundColor = [UIColor orangeColor];
_mLbl.textColor = [UIColor whiteColor];
_mLbl.font = [UIFont systemFontOfSize:35.];
_mLbl.textAlignment = NSTextAlignmentCenter;
CGFloat w1 = w0;
CGFloat h1 = self.view.bounds.size.height - h0;
CGFloat y1 = h0;
_mTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, y1, w1, h1)];
_mTableView.dataSource = self;
[_mTableView registerClass:[TableViewCell class] forCellReuseIdentifier:@"CELL"];
[self.view addSubview:_mLbl];
[self.view addSubview:_mTableView];
}
#pragma mark UITableViewDataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 20;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL" forIndexPath:indexPath];
[cell reloadData:indexPath.row];
return cell;
}
//接收事件
-(void)routerEvent:(id)info{
_mLbl.text = info;
}
@end
TableViewCell;
#import <UIKit/UIKit.h>
@interface TableViewCell : UITableViewCell
-(void)reloadData:(NSInteger)index;
@end
#import "TableViewCell.h"
#import "UIResponder+Router.h"
@interface TableViewCell ()
@property(assign, nonatomic)NSInteger mIndex;
@property(strong, nonatomic)UIButton *mBtn;
@end
@implementation TableViewCell
-(void)reloadData:(NSInteger)index{
_mIndex = index;
[_mBtn setTitle:[NSString stringWithFormat:@"%li",_mIndex] forState:UIControlStateNormal];
}
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
_mBtn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width*0.5, self.frame.size.height*0.8)];
_mBtn.backgroundColor = [UIColor purpleColor];
[_mBtn addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_mBtn];
}
return self;
}
//传递事件
-(void)btnAction{
[self routerEvent:[NSString stringWithFormat:@"%li",_mIndex]];
}
@end```
总得来说,拿到nextResponder就拿到了view的下一个事件响应者,至于怎么操作,可以自己拓展。