我试图在a的子视图中触发事件 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");
}
为了测试为什么这不起作用,我添加了 someAction:
ViewController和ViewController上的方法是最终处理从表视图单元子视图冒泡的事件的方法,即使Cell应该处理它。我检查了Cell是否在响应者链上,并且我已经验证了在单元格上方和下方的响应者链上的任何视图都会响应该事件,如果它们实现了 someAction:
方法。
到底发生了什么事?
这是一个展示它的项目 https://github.com/keithnorm/ResponderChainTest 这是预期的行为吗?我没有找到任何文档说明UITableViewCell的处理方式与其他UIResponder不同。
该单元格似乎要求其表格视图以获得许可。要改变它,你当然可以覆盖
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return [self respondsToSelector:action];
}
斯威夫特3:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return self.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:
方法被调用
我认为这是最简单的解决方案。如果您未指定目标,则事件将自动冒泡响应者链。
[[UIApplication sharedApplication]sendAction:@selector(customAction:) to:nil from:self forEvent:UIEventTypeTouches];