Предотвращение отключения UIButton от распространения событий касания

Мое приложение имеет две перекрывающиеся UIButtons. Верхняя кнопка может быть отключена время от времени. Однако в этом случае любые входящие в него события касания передаются вниз к основному виду, которое в моем случае является другой кнопкой.

Мне нужна верхняя кнопка, перехватывающая все касания и не позволяющая им дойти до нижней кнопки, даже в отключенном состоянии (я был бы счастлив, даже если это назначенное действие вызывается в отключенном состоянии).

До сих пор я пробовал:

[topButton setUserInteractionEnabled:YES];

и

[topButton setExclusiveTouch:YES];

хотя более поздний случай, вероятно, нежелателен, так как мне все еще нужна нижняя кнопка, отвечающая на события, если это первое нажатие. В любом случае никто из них не работает.

Ответ 1

Я добавил следующий метод для просмотра отключенной кнопки:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if (!self.watchButton.enabled &&
        [self.watchButton pointInside:[self convertPoint:point toView:self.watchButton]
                            withEvent:nil]) {
        return nil;
    }
    return [super hitTest:point withEvent:event];
}

Это хорошо работает с ячейками UITableView.

Ответ 2

То, что я сделал, это размещение UIImageView того же размера с UIButton только под UIButton. Тогда даже если вы отключите UIButton, события касания не распространяют UIImageView.

Ответ 3

Мне удалось получить эту работу, как мне было нужно, с немного измененной версией @kolyuchiy выше. Я перепробовал метод hitTest:withEvent: в моем подклассе UIButton, возвращая self, когда он отключен, а точка находится внутри рамки представления, так что прикосновение потребляется, но обработка события кнопки не вызывается.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if ( !self.enabled && [self pointInside:[self convertPoint:point toView:self] withEvent:event] )
    {
        return self;
    }
    return [super hitTest:point withEvent:event];
}

Ответ 4

После попытки @kolyuchiy (для чего требуется изменить поведение UIButton за пределами его области действия) и @patrick-lynch (который просто не работает для меня) решения пришли с более элегантным, что относится к подклассу UIButton

private static let dummyView: UIView = {
    let view = UIView(frame: .zero)
    view.userInteractionEnabled = true
    return view
}()

public override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    if !enabled && pointInside(point, withEvent: event) {
        return self.dynamicType.dummyView
    }
    return super.hitTest(point, withEvent: event)
}

Ответ 5

Создайте подкласс кнопки, затем переопределите эти методы, чтобы кнопка захватывала события, но игнорировала их, если для какого-либо свойства кнопки установлено значение NO:

touchesBegan:withEvent:
touchesCancelled:withEvent:
touchesEnded:withEvent:
touchesMoved:withEvent:

Это методы UIResponder.

Попросите их просто вызвать свой метод [super...], если вы хотите обработать событие, иначе просто не вызывайте его и не возвращайте, если хотите, чтобы события "съедали".

Также см. это в случае необходимости: Наблюдение за жесткими касаниями в UITableView

Ответ 6

Я знаю, что поздно, но я читал много подобных вопросов, и ни один из ответов, которые я читал, не был полезен для меня (некоторые из них, потому что не работали, а другие, потому что мне не нравилось это решение) поэтому я нашел лучшую форму решения, и я поделился ею здесь, чтобы помочь будущим пользователям, которые прочитали этот вопрос.

Решение

У меня всегда есть контейнер с некоторыми (или только одними) кнопками внутри. Поэтому я подключаю IBOutlet контейнера кнопок к UIViewController или UIView, с которым я работаю:

@property (weak, nonatomic) IBOutlet UIView *buttonsContainer;

И я установил ноль для распознавания жестов, как показано ниже:

[self.buttonsContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:nil]];

При этом обходном пути, если кнопка отключена, buttonsContainer фиксирует это событие и ничего не делает с ним.

Надеюсь, что это поможет.