Próbuję dowiedzieć się, jak to się robi we właściwy sposób . Próbowałem zobrazować sytuację:
Dodaję UITableView
jako podrzędny od a UIView
. Do UIView
reaguje na zaczepów i pinchGestureRecognizer
, ale gdy robi tak, tableview przestaje reagować na tych dwóch gestów (wciąż reaguje na kiepskie piwo).
Zrobiłem to z następującym kodem, ale oczywiście nie jest to przyjemne rozwiązanie i jestem pewien, że jest lepszy sposób. Jest to umieszczane w UIView
(nadzorze):
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if([super hitTest:point withEvent:event] == self) {
for (id gesture in self.gestureRecognizers) {
[gesture setEnabled:YES];
}
return self;
}
for (id gesture in self.gestureRecognizers) {
[gesture setEnabled:NO];
}
return [self.subviews lastObject];
}
objective-c
ios
uiview
uigesturerecognizer
uiresponder
andershqst
źródło
źródło
hitTest:withEvent:
lubpointInside:withEvent:
.return !(touch.view == givenView);
Jeśli chcesz po prostu wykluczyć dany widok lubreturn !(touch.view.tag == kTagNumReservedForExcludingViews);
gdy chcesz zatrzymać aparat rozpoznający przetwarzający dotyk na całej grupie różnych podwidoków.- (BOOL)isDescendantOfView:(UIView *)view
. Działa to również dobrze w- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
przypadku podklasy UIGestureRecognizer.Domyślnym zachowaniem jest blokowanie zdarzeń dotyku w widokach podrzędnych. Możesz zmienić to zachowanie:
UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)]; r.cancelsTouchesInView = NO; [agentPicker addGestureRecognizer:r];
źródło
translationInView
metody. Dlatego implementacja wspomnianej powyżej metody UIGestureRecognizerDelegate spowodowałaby jedynie awarię z błędem... unrecognized selector sent to blah
. Aby sprawdzić, używać coś takiego:CGRectContainsPoint(subview.bounds, [recognizer locationInView:subview])
.Wyświetlałem rozwijany widok podrzędny, który miał własny widok tabeli. W rezultacie
touch.view
czasami zwracały klasy, takie jakUITableViewCell
. Musiałem przejść przez superklasę (y), aby upewnić się, że jest to podklasa, o której myślałem:-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { UIView *view = touch.view; while (view.class != UIView.class) { // Check if superclass is of type dropdown if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own NSLog(@"Is of type dropdown; returning NO"); return NO; } else { view = view.superview; } } return YES; }
źródło
Opierając się na @Pin Shih Wang odpowiedź . Ignorujemy wszystkie dotknięcia inne niż te w widoku zawierającym rozpoznawanie gestów dotknięcia. Wszystkie dotknięcia są przekazywane do hierarchii widoków tak normalnie, jak ustawiliśmy
tapGestureRecognizer.cancelsTouchesInView = false
. Oto kod w Swift3 / 4:func ensureBackgroundTapDismissesKeyboard() { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap)) tapGestureRecognizer.cancelsTouchesInView = false self.view.addGestureRecognizer(tapGestureRecognizer) } @objc func handleTap(recognizer: UIGestureRecognizer) { let location = recognizer.location(in: self.view) let hitTestView = self.view.hitTest(location, with: UIEvent()) if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) { // I dismiss the keyboard on a tap on the scroll view // REPLACE with own logic self.view.endEditing(true) } }
źródło
UISwipeActionStandardButton
? Próbowałem z.some(UISwipeActionStandardButton)
Jedną z możliwości jest utworzenie podklasy aparatu rozpoznawania gestów (jeśli jeszcze tego nie zrobiłeś) i zastąpienie go
-touchesBegan:withEvent:
tak, aby określał, czy każdy dotyk rozpoczął się w wykluczonym podglądzie i wywołuje-ignoreTouch:forEvent:
ten dotyk, jeśli tak się stało.Oczywiście musisz również dodać właściwość, aby śledzić wykluczony podwidok lub, być może lepiej, tablicę wykluczonych podglądów podrzędnych.
źródło
Można to zrobić bez dziedziczenia żadnej klasy.
Możesz sprawdzić gestRecognizers w selektorze wywołań zwrotnych gestów
jeśli view.gestureRecognizers nie zawiera Twojego gestRecognizer, po prostu go zignoruj
na przykład
- (void)viewDidLoad { UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; singleTapGesture.numberOfTapsRequired = 1; }
sprawdź tutaj view.gestureRecognizers
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer { UIEvent *event = [[UIEvent alloc] init]; CGPoint location = [gestureRecognizer locationInView:self.view]; //check actually view you hit via hitTest UIView *view = [self.view hitTest:location withEvent:event]; if ([view.gestureRecognizers containsObject:gestureRecognizer]) { //your UIView //do something } else { //your UITableView or some thing else... //ignore } }
źródło
singleTapGesture.cancelsTouchesInView = NO;
dodany doviewDidLoad
powyżejStworzyłem podklasę UIGestureRecognizer przeznaczoną do blokowania wszystkich aparatów rozpoznawania gestów dołączonych do superwizji określonego widoku.
To część mojego projektu WEPopover. Znajdziesz go tutaj .
źródło
zaimplementuj delegata dla wszystkich modułów rozpoznawania elementu parentView i umieść metodę gestRecognizer w delegacie, który jest odpowiedzialny za jednoczesne wyzwalanie modułów rozpoznawania:
func gestureRecognizer(UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool { if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) { return true } else { return false }
}
Możesz użyć metod niepowodzenia, jeśli chcesz, aby dzieci były wyzwalane, ale nie nadrzędne rozpoznawanie:
https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate
źródło
Robiłem też popover i tak to zrobiłem
func didTap(sender: UITapGestureRecognizer) { let tapLocation = sender.locationInView(tableView) if let _ = tableView.indexPathForRowAtPoint(tapLocation) { sender.cancelsTouchesInView = false } else { delegate?.menuDimissed() } }
źródło
Możesz to wyłączyć i włączyć .... w moim kodzie zrobiłem coś takiego, ponieważ musiałem to wyłączyć, gdy klawiatura się nie wyświetlała, możesz zastosować to do swojej sytuacji:
nazwij to viewdidload itp:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil]; [center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil];
następnie utwórz dwie metody:
-(void) notifyShowKeyboard:(NSNotification *)inNotification { tap.enabled=true; // turn the gesture on } -(void) notifyHideKeyboard:(NSNotification *)inNotification { tap.enabled=false; //turn the gesture off so it wont consume the touch event }
To powoduje wyłączenie kranu. Musiałem jednak zmienić tap w zmienną instancji i zwolnić ją w trybie dealloc.
źródło