Как игнорировать события касания и передавать их другим объектам UIControl подзаголовка?

У меня есть пользовательский UIViewController, UIView которого занимает угол экрана, но большая часть его прозрачна, за исключением тех частей, которые имеют некоторые кнопки и прочее. Из-за расположения объектов на этом представлении рамка представления может закрывать некоторые кнопки под ним. Я хочу иметь возможность игнорировать любые прикосновения к этой точке зрения, если они не касаются чего-либо важного, но я, кажется, только могу пройти по фактическим событиям касания (затрагивает вещи Enned/nextResponder). Если у меня есть UIButton или что-то вроде того, которое не использует touchesEnded, как мне передать событие касания вместе с этим?

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

[self.nextResponder touchesEnded:touches withEvent:event];

и в типах UIControl.

Ответ 1

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

Если у вас есть ссылка на представление под представлением, чтобы игнорировать:

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

    // If the hitView is THIS view, return the view that you want to receive the touch instead:
    if (hitView == self) {
        return otherView;
    }
    // Else return the hitView (as it could be one of this view buttons):
    return hitView;
}

Если у вас нет ссылки на представление:

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

    // If the hitView is THIS view, return nil and allow hitTest:withEvent: to
    // continue traversing the hierarchy to find the underlying view.
    if (hitView == self) {
        return nil;
    }
    // Else return the hitView (as it could be one of this view buttons):
    return hitView;
}

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

Ответ 2

Быстрый ответ:

Вы можете создать подкласс UIView, IgnoreTouchView. В раскадровке установите его в виде (ых) просмотра VC, которые вы хотите передать:

class IgnoreTouchView : UIView {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let hitView = super.hitTest(point, with: event)
        if hitView == self {
            return nil
        }
        return hitView
    }
}

Обратите внимание, что вы должны установить UserInteractionEnabled в true, для рассматриваемого UIView!

Ответ 3

Я не нашел хороший способ передать события UITouch между объектами. Что обычно работает лучше, так это реализовать hitTest и вернуть нуль, если точка не в том представлении, которое вы хотите обработать:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

Ответ 4

Это старый вопрос, и он поднимается вверху поисков. Итак, я думал, что опубликую еще одно возможное решение, которое может работать лучше для вашей ситуации. В моем случае я хотел перетащить ярлык поверх другого ярлыка, и я хотел получить ярлык ниже в hitTest. Самое простое - установить userInteractionEnabled на NO или false, а затем сделать свой hitTest, а затем снова установить его, если вам нужно снова его переместить. Здесь образец кода в Swift:

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch = touches.first
    let location = touch?.locationInView(self.view)
    self.label1.userInteractionEnabled = false
    let view = self.view.hitTest(location!, withEvent: nil) as? UILabel
    print(view?.text)
    self.label1.userInteractionEnabled = true
}

Ответ 5

Моя проблема была схожа: у меня был UIControl со сложными сенсорными респондентами, но он был смешным, когда встроен в прокрутку...

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

Мое решение:

Создайте делегатский протокол для didBeginInteraction и didEndInteraction в представлении sub.

Вызвать делегат .didBeginInteraction от touchhesBegan

Вызов delegate.didEndInteraction from touchesEnded и touchsCancelled

В родительском контроллере реализовайте протокол didBegin и didEnd, установите делегат

Затем установите scrollView.scrollEnabled = NO в didBegin, scrollEnabled = YES в didEnd.

Надеюсь, это поможет кому-то с немного другим вариантом использования, чем заданный вопрос!