UITableViewCell пропущен в цепочке ответчиков
Я пытаюсь вызвать событие в subview 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 - это тот, который завершает обработку события, которое пузырится из подматрицы ячейки таблицы, хотя Ячейка должна справиться с этим. Я проверил, что ячейка находится в цепочке ответчиков, и я проверил, что любые представления в цепочке ответчиков, как над, так и под ячейкой, будут реагировать на событие, если они реализуют метод someAction:
.
Что здесь происходит?
Здесь проект, который показывает его https://github.com/keithnorm/ResponderChainTest Является ли это ожидаемое поведение каким-то образом? Я не нашел никаких документов, в которых говорится, что UITableViewCell обрабатывается иначе, чем другие файлы UIResponder.
Ответы
Ответ 1
Кажется, что ячейка запрашивает разрешение для своего табличного представления. Чтобы изменить это, вы можете, конечно, переопределить
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return [self respondsToSelector:action];
}
Swift 3, 4, 5:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return self.responds(to: action)
}
Ответ 2
Я пришел к выводу, что это либо ошибка, либо недокументированное намеренное поведение. Во всяком случае, я закончил грубую силу, установив ее, ответив на событие в подвью, а затем вручную распространив сообщение на цепочку ответчиков. Что-то вроде:
- (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.
Я по-прежнему приветствую любые другие идеи, если кто-то еще это оценит, но это лучшее, что у меня есть сейчас.
Ответ 3
сделайте это
@implementation ContentView
// uncomment this to see event caught by the cell 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:
метод вызывается
Ответ 4
Вы можете изменить код в View.m как
[button addTarget:nil action:@selector(customEventFired:) forControlEvents:(1 << 24)];
к
[button addTarget:cell action:@selector(customEventFired:) forControlEvents:(1 << 24)];
Ответ 5
Я думаю, что это самое простое решение. Если вы не укажете цель, событие автоматически запустит цепочку ответчиков.
[[UIApplication sharedApplication]sendAction:@selector(customAction:) to:nil from:self forEvent:UIEventTypeTouches];