Пересылка UIGesture в режим просмотра
Я работаю над приложением iphone (iOS 4.0 или новее) и испытываю некоторые проблемы с сенсорным управлением между несколькими видами. У меня есть структура представления, подобная этой
---> A superView
|
---> SubView - A
|
---> SubView - B (exactly on top of A, completely blocking A).
![enter image description here]()
В основном у меня есть супервизор, а subviews sibling A и B. B имеет тот же фрейм, что и A, и, следовательно, полностью скрывают A.
Теперь мое требование таково.
- SubView B должен получить все салфетки и нажмите (один и два)
жесты.
- SubView A должен получать все жесты пинча.
Вот как я добавил распознаватели жестов в представления
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];
[leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];
leftSwipe.delegate = self;
[bView addGestureRecognizer:leftSwipe];
[leftSwipe release];
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];
[rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];
rightSwipe.delegate = self;
[bView addGestureRecognizer:rightSwipe];
[rightSwipe release];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
pinch.delegate = self;
[aView addGestureRecognizer:pinch];
[pinch release];
Я провел некоторое исследование, и для меня UIGestureRecognizerDelegate
выглядел многообещающим, и я реализовал метод делегата
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
Я возвратил NO для SubView B, надеясь, что основное представление получит это событие. Нет такой удачи, хотя
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] && [gestureRecognizer view] == bView) {
NSLog(@"pinchGesture");
//bView.userInteractionEnabled = NO;
return NO;
}
return YES;
}
Затем я отключил взаимодействие пользователя SubView B внутри обратного вызова делегата (код комментария в вышеупомянутом блоке), когда распознается жест щепотки, в надежде, что оставшаяся часть жестов будет получена SubView A. Нет такой удачи и там.
Так вот, где я сейчас стою. Я видел этот вопрос, где принятый ответ включает свойство cancelsTouchesInView
. Но я считаю, что cancelsTouchesInView
только отменяет конкретное событие касания, не пересылает его.
Любой другой способ достичь моего требования? Я готов работать над тем, что вы предлагаете.
РЕДАКТИРОВАТЬ: ВРЕМЯ ВРЕМЕНИ
Мой так называемый subView A на самом деле является экземпляром стороннего класса View class, который отнимает все внимание, и я не контролирую никаких жестов на нем. Я хочу различную реализацию для левого и правого салфетки, и я хочу, чтобы щепотка, кран и т.д. Работали так же, как и с этим сторонним видом. Поэтому я поставил точку зрения над A (SubView B), чтобы получить левый и правый щелчки. Но теперь я хочу перенаправить другие события жестов в базовую библиотеку.
Ответы
Ответ 1
Если я правильно исправлю вашу проблему, вы можете просто добавить еще один, четкий вид с прямоугольником, такой же, как вы, A и B, и реализовать на нем все жесты: когда вы делаете жест жестки, управляйте subView A, проведите пальцем по экрану и коснитесь (одиночные и двойные) - управление subView B. Вы можете сделать это по-разному: с помощью указателей или просто посылая возвращенный жест методу в классе, который контролирует ваш под просмотр.
например:
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];
[leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];
leftSwipe.delegate = subViewAcontroller;
[clearView addGestureRecognizer:leftSwipe];
[leftSwipe release];
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];
[rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];
rightSwipe.delegate = subViewAcontroller;
[clearView addGestureRecognizer:rightSwipe];
[rightSwipe release];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
pinch.delegate = subViewBcontroller;
[clearView addGestureRecognizer:pinch];
[pinch release];
или
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
NSLog(@"pinchGesture");
[subViewBcontroller solvePinchGesture: gestureRecognizer];
}
//etc
return YES;
}
Ответ 2
Жест жестокости никогда не будет принят aView, потому что вы считаете, что иерархия неверна.
---> A superView
|
---> SubView - A
|
---> SubView - B (exactly on top of A, completely blocking A).
bView будет захватывать все множественные касания, включая жест щепотки, но bView не будет обрабатывать жест щепотки, поэтому он передаст его следующему ответчику в цепочке ответчика, то есть супервидео bView или viewController для bView. Событие пинча никогда не будет передаваться его представлениям со стороны, потому что они параллельны (отношения родительский-дочерний или view-viewController).
Вы можете изменить свою иерархию представлений, как показано ниже:
---> A superView
|
---> SubView - A
|
---> SubView - B (child view of b, exactly on top of A, completely blocking A)
- (void)viewDidLoad {
[super viewDidLoad];
aView = [[UIView alloc] initWithFrame:self.view.bounds];
aView.backgroundColor = [UIColor blueColor];
bView = [[UIView alloc] initWithFrame:self.view.bounds];
bView.backgroundColor = [UIColor redColor];
[self.view addSubview:aView];
[aView addSubview:bView];
UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];
[leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];
leftSwipe.delegate = self;
[bView addGestureRecognizer:leftSwipe];
UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];
[rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];
rightSwipe.delegate = self;
[bView addGestureRecognizer:rightSwipe];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];
pinch.delegate = self;
[aView addGestureRecognizer:pinch];
}
Пожалуйста, получите более подробную информацию по ссылке:
https://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/EventsiPhoneOS/EventsiPhoneOS.html#//apple_ref/doc/uid/TP40009541-CH2-SW1
- > Важное замечание о событии, проходящем в цепочке ответчиков
"Когда система отправляет событие касания, она сначала отправляет ее в определенное представление. Для событий касания это представление - это тот, который возвращается hitTest: withEvent:; для" встряхивания "событий-событий, событий дистанционного управления, сообщений о действиях, и сообщениями меню редактирования, это представление является первым ответчиком. Если начальный вид не обрабатывает событие, он перемещается по цепочке ответчиков по определенному пути:
- Тестирование или первый ответчик передает запрос или сообщение его контроллеру вида, если он имеет один; если в представлении нет контроллера вида, он передает событие или сообщение в его супервизор.
- Если диспетчер представлений или его просмотр не может обрабатывать событие или сообщение, он передает его в супервизор представления.
- Каждый последующий супервизор в иерархии следует шаблону, описанному в первых двух шагах, если он не может обрабатывать событие или сообщение.
- Верхний вид в иерархии представления, если он не обрабатывает событие или сообщение, передает его объекту окна для обработки.
- Объект UIWindow, если он не обрабатывает событие или сообщение, передает его объекту приложения singleton. "
Мой ответ выше - это не единственное решение, что вам нужно сделать, это сделать салфетки и манипулировать жесты логикой в той же цепочке ответчиков, чтобы событие жестов с жестким пинчем передавалось правильному ответчику. Например, вы можете опустить subview b и добавить салфетки влево/вправо для супервизора aView.
Ответ 3
Я сделал что-то подобное некоторое время назад. Я хотел сделать две разные вещи одним пальцем и двумя или несколькими пальцами. Моему решению может потребоваться некоторая настройка для вас, и я не могу гарантировать, что все будет работать точно так же в вашей среде кода. Я не нашел надлежащей документации hitTest и почему она называется несколько раз подряд. Поэтому я провел некоторое тестирование и пришел к решению, как отделить один и несколько пальцев жесты, которые очень хорошо работали для моих нужд.
У меня была эта иерархия представлений:
---> A superView
|
---> ScrollView - A - all touches
|
---> ScrollView - B - only two+ finger scroll (exactly on top of A, completely blocking A).
Я реализовал переключатель в hitTest супервизора:
BOOL endDrag; // indicates scrollviewB did finish
BOOL shouldClearHitTest; // bool to help calling the method clearHitTest only once.
BOOL multiTouch; // needed for the method clearHitTest to know if a multi-touch is detected or not
NSMutableArray *events; // store all events within one eventloop/touch;
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!endDrag) {
if (!shouldClearHitTest) { // as hitTest will be called multible times in one event-loop and i need all events, i will clean the temporaries when everything is done
shouldClearHitTest = YES;
[[NSRunLoop mainRunLoop] performSelector:@selector(clearHitTest) target:self argument:nil order:1 modes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
}
[events addObject:event]; // store the events so i can access them after all hittests for one touch are evaluated
if (event.type == UIEventTypeTouches && ([_events count] > 3 || [[event allTouches] count] > 0 || _currentEvent)) { // two or more fingers detected. at least for my view hierarchy
multiTouch = YES;
return scrollViewB;
}
}else {
endDrag = NO;
}
return scrollViewA;
}
- (void)clearHitTest {
if (shouldClearHitTest) {
shouldClearHitTest = NO;
[events removeAllObjects];
if (multiTouch) {
// Do some special stuff for multiTouch
}
multiTouch = NO;
}
}
Ответ 4
Я предлагаю вам использовать нижеприведенную строку кода, где это может вам помочь.
//--->for bview gesture to detect swipe
[pinch requireGestureRecognizerToFail:leftSwipe]; &&
[pinch requireGestureRecognizerToFail:rightSwipe];
//--->for aview gesture to detect pinch
[rightSwipe requireGestureRecognizerToFail:rightSwipe]; ||
[leftSwipe requireGestureRecognizerToFail:pinch];
Ответ 5
Если bView имеет жест жесткости. Из действия жестов bView pinch, если вы назовёте действие жестов aView, затем...
UIPinchGestureRecognizer *pinchA = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchA:)];
[aView addGestureRecognizer:pinchA];
[pinchA release];
UIPinchGestureRecognizer *pinchB = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchB:)];
[bView addGestureRecognizer:pinchB];
[pinchB release];
-(void)handlePinchA:(UIGestureRecognizer*)gestureRecognizer
{
NSLog(@"handlePinch on A");
}
-(void)handlePinchB:(UIGestureRecognizer*)gestureRecognizer
{
NSLog(@"handlePinch on B");
[self handlePinchA:gestureRecognizer];
}
aView - это библиотека thirdParty. Можете ли вы вызвать метод handlePinchA извне? NSLog gestureRecognizers печатает меня action = handlePinchA
NSLog(@"gestureRecognizers %@", [aView gestureRecognizers]);
Печать меня:
gestureRecognizers (
"<UIPinchGestureRecognizer: 0x8b3e500; state = Possible; view = <UIView 0x8b2f470>; target= <(action=handlePinchA:, target=....