it-swarm.com.ru

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

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

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

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

на типах UIControl. 

59
Chris C

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

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

129
Stuart

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

Вы можете создать подкласс 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!

10
Kevin

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

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

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

В Свифте:  

yourView.isUserInteractionEnabled = false
5
Melkon

Это старый вопрос, и он поднимается вверху поисков. Итак, я думал, что опубликую другое возможное решение, которое может работать лучше для вашей ситуации. В моем случае я хотел перетащить ярлык поверх другого ярлыка, и я хотел получить ярлык ниже в 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
}
3
smileBot

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

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

Мое решение:

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

Вызовите Delegate.didBeginInteraction от touchesBegan

Вызовите Delegate.didEndInteraction от прикосновения закругленного и прикосновения отменено

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

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

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

0
Lytic