Запретить отключенному UIButton распространять события касания

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

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

Пока я пробовал:

[topButton setUserInteractionEnabled:YES];

и

[topButton setExclusiveTouch:YES];

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


person Mihai Damian    schedule 13.01.2010    source источник


Ответы (6)


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

- (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.

person kolyuchiy    schedule 22.08.2012

Мне удалось заставить это работать, как мне нужно, с немного измененной версией ответа @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];
}

Быстрая версия:

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    if !isEnabled, self.point(inside: point, with: event) {
        return self
    }
    return super.hitTest(point, with: event)
}
person Patrick Lynch    schedule 16.07.2015

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

Решение

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

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

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

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

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

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

person Marc Estrada    schedule 05.06.2018

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

person heemin    schedule 03.02.2012
comment
На самом деле это самое простое и быстрое решение - person codingFriend1; 11.07.2017

После попытки @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)
}
person rshev    schedule 24.11.2016

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

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

Это методы UIResponder.

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

Также см. Это, если это необходимо: Наблюдение за несколькими щипками сенсорные жесты в UITableView

person Nimrod    schedule 14.01.2010
comment
Похоже, эти методы вообще не вызываются, когда кнопка отключена. - person Mihai Damian; 14.01.2010
comment
Да, это то, что я понял (вот почему я сказал некоторое свойство), поэтому вам может потребоваться либо использовать второй метод, либо сделать что-то другое, кроме отключения кнопки, например, имитировать ее отключение каким-либо образом. Второй метод, вероятно, будет проблемой, поскольку UIApplication (который вызывает sendEvent в окне), вероятно, игнорирует отключенные UIControls. - person Nimrod; 14.01.2010