Как игнорировать сенсорные события и передавать их объектам UIControl другого подпредставления? - PullRequest
62 голосов
/ 11 октября 2011

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

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

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

также для типов UIControl.

Ответы [ 6 ]

131 голосов
/ 11 октября 2011

Вероятно, лучший способ сделать это - переопределить 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's 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's buttons):
    return hitView;
}

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

11 голосов
/ 03 января 2017

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

Вы можете создать подкласс UIView, IgnoreTouchView. В раскадровке установите его в представлениях ВК, которые вы хотите пройти через прикосновения:

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!

8 голосов
/ 28 августа 2018

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

В Swift:

yourView.isUserInteractionEnabled = false
7 голосов
/ 11 октября 2011

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

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
3 голосов
/ 28 февраля 2016

Это старый вопрос, и он поднимается вверху поисков.Итак, я думал, что опубликую другое возможное решение, которое может работать лучше для вашей ситуации.В моем случае я хотел перетащить ярлык поверх другого ярлыка, и я хотел получить ярлык ниже в hitTest.Самое простое, что нужно сделать, это установить userInteractionEnabled в NO или false, затем выполнить хит-тест, а затем снова установить его, если вам нужно переместить его снова.Вот пример кода в 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
}
0 голосов
/ 15 февраля 2017

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

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

Мое решение:

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

Вызовите делегат.

Вызовите делегат.didEndInteraction от прикосновений Закругленных и касаний Отменено

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

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

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

...