UITableViewCell跳过响应者链
我试图触发一个UITableViewCell
子视图中的事件,并让它冒泡响应链,并由自定义的UITableViewCell
子类处理。
基本上:
SomeView.m (这是UITableViewCell
的子视图)
[self.button addTarget:nil action:@selector(someAction:) events:UIControlEventTouchUpInside]
SomeCustomCell.m
- (void)someAction:(id)sender { NSLog(@"cool, the event bubbled up to the cell"); }
为了testing为什么这不起作用,我在ViewController中添加了someAction:
方法,而ViewController是最终处理从表视图单元格子视图中冒出的事件的一个,即使Cell应该处理它。 我已经检查过Cell是否在响应链上,并且我已经validation过,在响应者链上和响应者链上的任何视图都会响应事件,如果他们实现someAction:
方法的话。
这到底是怎么回事?
这是一个项目,显示它https://github.com/keithnorm/ResponderChainTest这种预期的行为不知何故? 我还没有find任何文档说明UITableViewCell的处理任何不同于其他UIResponder的。
该单元格似乎要求其表视图的权限。 要改变,你当然可以覆盖
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { return [self respondsToSelector:action]; }
Swift 3:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { return responds(to: action) }
我已经得出结论,这是一个错误或无证的预期行为。 无论如何,我最终通过在子视图中响应事件来强制修复它,然后手动将消息传播到响应者链中。 就像是:
- (void)customEventFired:(id)sender { UIResponder *nextResponder = self.nextResponder; while (nextResponder) { if ([nextResponder respondsToSelector:@selector(customEventFired:)]) { [nextResponder performSelector:@selector(customEventFired:) withObject:sender]; break; } nextResponder = nextResponder.nextResponder; } }
我也更新了我的演示项目,以显示我如何使用此“修复” https://github.com/keithnorm/ResponderChainTest 。
如果其他人想出来,我仍然欢迎任何其他的想法,但这是我现在最好的。
您可以将View.m中的代码更改为
[button addTarget:nil action:@selector(customEventFired:) forControlEvents:(1 << 24)];
至
[button addTarget:cell action:@selector(customEventFired:) forControlEvents:(1 << 24)];
这样做
@implementation ContentView // uncomment this to see event caught by the cell's subview - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(self) { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setTitle:@"Click" forState:UIControlStateNormal]; [button setBackgroundColor:[UIColor blueColor]]; [button addTarget:self action:@selector(customEventFired:) forControlEvents:UIControlEventTouchUpInside]; button.frame = CGRectMake(4, 5, 100, 44); [self addSubview:button]; } return self; } - (void)customEventFired:(id)sender { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Event Triggered in cell subview" message:@"so far so good..." delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil]; [alertView show]; } @end
现在customEventFired:
方法被调用
我认为这是最简单的解决scheme。 如果您没有指定目标,则事件将自动向响应者链上鼓吹。
[[UIApplication sharedApplication]sendAction:@selector(customAction:) to:nil from:self forEvent:UIEventTypeTouches];