UIView - "взаимодействие с пользователем включено" ложно для родителя, но верно для потомка?

Похоже, что userInteractionEnabled=NO в родительском представлении предотвратит взаимодействие с пользователем во всех подпредставлениях. Это правильно? Есть ли способ обойти это?

4 ответа

Решение

Это верно, userInteractionEnabled, установленный в NO в родительском представлении, будет каскадно переходить ко всем подпредставлениям. Если вам нужно, чтобы некоторые подпредставления включили взаимодействие, но не другие, вы можете разделить ваши подпредставления на два родительских представления: одно с userInteractionEnabled = YES, а другое NO. Затем поместите эти два родительских представления в основной вид.

Вы можете создать подкласс UIView и переопределить hitTest:withEvent: таким образом, чтобы передать сенсорные события в указанное вами представление (_backView):

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *view = [super hitTest:point withEvent:event];

    if (view == self) {
        view = _backView;
    }

    return view;
}

Если событие касания должно было обрабатываться этим представлением, оно будет передано "_backView" (это может быть IBOutlet, чтобы его можно было установить с помощью построителя интерфейса); и если это должно было быть обработано любым дочерним представлением, просто верните этого потомка (результат [super hitTest:point withEvent:event];)

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

Лучшим решением может быть упомянутое в разделе "Отключить касания на фоне UIView", чтобы кнопки на нижних представлениях можно было нажимать. -pointInside:withEvent:; по сравнению с предыдущим решением лучше, если вам не нужно указывать _backView для получения событий (событие просто передается следующему представлению в цепочке)! недостатком может быть то, что нам нужно выполнить -pointInside:withEvent: на всех подпредставлениях (хотя может иметь незначительные накладные расходы)

Вот решение. Создайте класс, унаследованный от "UIView", и напишите функцию, которая переопределяет "внутреннюю точку"

class TTSView: UIView {


    
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
          for view in self.subviews {
               if view.isUserInteractionEnabled, view.point(inside: self.convert(point, to: view), with: event) {
                   return true
               }
           }

           return false
     }

}

затем в раскадровке или xib супервизор должен использовать этот класс

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

Ни одно из вышеуказанных решений не помогло мне, но я нашел другое решение. Перейдите к раскадровке и добавьте tapGestureRecognizer в родительское представление, чтобы поглощать прикосновения к родительскому представлению. Задача решена!

Я просто наткнулся на странную ситуацию. У меня есть UIView (назовите это, V), который имеет UIButton в качестве подпредставления. Назовите эту кнопку UIB, кнопка X. Ниже приведен метод, который я использую для цели / селектора кнопки X. Самым ниже является представление V. Параметр отправителя - кнопка X.

Ситуация, которая вызывает у меня проблему, заключается в том, что если я коснусь другой кнопки в моем пользовательском интерфейсе (на панели навигации, назовите эту кнопку Y), а затем очень быстро коснитесь кнопки X, где действие кнопки Y отключает вид V, я все равно получаю сенсорное событие отправлено на кнопку X.

- (void) buttonAction: (UIButton *) sender
{
    NSLog(@"superview: %d", sender.superview.userInteractionEnabled);  
    NSLog(@"button itself: %d", sender.userInteractionEnabled);

    // <snip>
}

Вот вывод:

2014-12-19 16: 57: 53.826 MyApp [6161: 960615] superview: 0
2014-12-19 16: 57: 53.826 MyApp [6161: 960615] сама кнопка: 1

То есть, действие кнопки произошло, а в суперпредставлении кнопки было отключено взаимодействие с пользователем! И в подвиде все еще было включено взаимодействие с пользователем!!

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

Мысли?

Мой текущий обходной путь приведен ниже, но кажется странным, что это необходимо!

- (void) buttonAction: (id) sender
{
    NSLog(@"superview: %d", sender.superview.userInteractionEnabled);  
    NSLog(@"button itself: %d", sender.userInteractionEnabled);
    if (! self.userInteractionEnabled) return;

    // <snip>
}

Я делаю это в xib, который является моим "настраиваемым контроллером оповещений".

for (UIView *subview in self.superview.subviews) {

    if (![subview isEqual:self]) {
        subview.userInteractionEnabled = NO;
    }
}
Другие вопросы по тегам