Исключить подпункты из UIGestureRecognizer
У меня есть UIView ( "контейнерный вид" ), который содержит несколько "подпунктов". Я хочу добавить UITapGestureRecognizer в представление контейнера, так что он активируется, когда я касаюсь области внутри контейнера, но вне подзонов.
В настоящий момент прикосновение в любом месте контейнера, в том числе внутри подзонов, активирует распознаватель жестов.
Реализация выглядит примерно так:
В контроллере:
ContainerView *containerView = [[ContainerView alloc] initWithSubViews:array];
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc] initWithTarget:self action:@selector(someSelector)];
[containerView addGestureRecognizer:tap];
[self.view addSubView:containerView];
В ContainerView.m
-(id)initWithSubviews:(NSArray *)array {
for (subView *s in array) {
[self addSubView:s];
}
return self;
}
Я думаю, что проблема возникает из-за того, что распознаватель жестов добавляется после подзапросов. Если это так, то решение потребует разбить метод initWithSubViews на два отдельных, которые я бы предпочел избежать.
Спасибо
Ответы
Ответ 1
iOS 6 представляет новую новую функцию, которая решает эту точную проблему - UIView (subview) может возвращать NO из gestureRecognizerShouldBegin:
(распознаватель жестов, прикрепленный к супервину). Действительно, это значение по умолчанию для некоторых подклассов UIView в отношении некоторых распознавателей жестов уже (например, UIButton относительно UITapGestureRecognizer, прикрепленного к супервину).
Смотрите мою книгу по этой теме: http://www.apeth.com/iOSBook/ch18.html#_gesture_recognizers
Ответ 2
Я использовал простой способ ниже. Он работает правильно!
Реализовать функцию UIGestureRecognizerDelegate, принимать только прикосновения к супервизу, не принимать прикосновения к subviews:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view != _mySuperView) { // accept only touchs on superview, not accept touchs on subviews
return NO;
}
return YES;
}
Ответ 3
Мне удалось заставить его работать, выполнив следующие действия:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)];
// ...
-(void) tapGestureHandler:(UITapGestureRecognizer *)sender {
CGPoint point = [sender locationInView:sender.view];
UIView *viewTouched = [sender.view hitTest:point withEvent:nil];
if ([viewTouched isKindOfClass:[ThingIDontWantTouched class]]) {
// Do nothing;
} else {
// respond to touch action
}
}
Ответ 4
Не забудьте добавить и установить метод делегата -
В ваш UIViewController.h файл входит этот делегат
@interface YourViewController: UIViewController<UIGestureRecogniserDelegate>
Затем, когда вы создаете свой объект tapGesture (например, в viewDidLoad)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(actionMethodYouWantToHappenOnTap)];
tap.delegate = self; //Remember to set delegate! Otherwise the delegate method won't get called.
[self.view addGestureRecognizer:tap];
Помня о том, чтобы установить метод делегирования tap.delegate = self;
, затем будет отключен метод делегата для подключения.
В этом методе вы обрабатываете, когда хотите использовать распознавание жеста tap, в моем коде я хотел, чтобы он игнорировал ответвление, если было видно какое-то подвью
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (!mySubview.hidden){
return NO; //This fired if said subview was visible, though whatever the condition of where and when you want tap to work, can be handled within this delegate method.
}
return YES;
}
Я надеюсь, что это поможет кому-то еще с той же проблемой. Помнить, что установить метод делегата, который я нашел, было легко упустить.
Приветствия
Ответ 5
Множество ответов, добавив другое альтернативное решение. Инициализируйте тег представления подзонов, которые вы не хотите получать касаниями, начиная с 1 и выполните следующие действия:
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
tap.delegate = self;
[self.view addGestureRecognizer:tap];
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view.tag == 1) {
return NO;
}
return YES;
}
-(void)handleTap:(id)sender
{
//Handle tap...
}
Таким образом, сенсорный жест будет получен только из тех видов, которые вам нужны.
Ответ 6
Если вы добавили UITapGestureRecognizer
для ContainerView, он должен ответить со всем ContainerView. Он не будет возражать против его подсмотров.
Проверьте местоположение Жест, если оно находится в позиции вашего просмотра, просто пропустите действия жестов.
- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer {
CGPoint tapPoint = [gestureRecognizer locationInView:nil];
//check your tapPoint contains ur subview frame, skip.else do ur actions
}
Ответ 7
ДОБАВЛЕН:
Я просто подумал о чем-то лучшем.
в вашем обработчике
-(void)tapGestureHandler:(UITapGestureHandler)gesture
проверьте, является ли gesture.view супервидом.
он будет возвращать subviews, если subviews будут прослушиваться.
=============================================== =====
Я бы предложил переопределить внутри супервизора.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
это вызывается, чтобы определить, попадает ли жест в представление
см. ответ на этот вопрос, чтобы посмотреть, как он работает по умолчанию.
Обработка событий для iOS - как hitTest: withEvent: и pointInside: withEvent: связаны?
вы можете проверить, находится ли точка в любом из ее подзонов. если да, верните нуль, еще верните self.
ИЛИ
в каждом из подзонов, добавьте распознаватель прокси-сервера, который ничего не делает. признак распознавания жестов подвью отменяет распознаватель жестов своего супервизора по умолчанию. я бы следил за памятью, если есть много подпунктов.