Muszę zaimplementować funkcję, która będzie wywoływać kod po dwukrotnym dotknięciu self.view (widoku UIViewCotroller
). Ale problem polega na tym, że mam inny obiekt UI w tym widoku i nie chcę dołączać żadnego obiektu rozpoznawania do wszystkich z nich. Poniżej znalazłem tę metodę, jak wykonać gest na moim widoku i wiem, jak to działa. W tej chwili stoję przed handicapem, który sposób wybrać, aby utworzyć ten aparat rozpoznający, ignorując podgląd podrzędny. Jakieś pomysły? Dzięki.
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:doubleTap];
ios
uitapgesturerecognizer
Matrosov Alexander
źródło
źródło
Odpowiedzi:
Powinieneś przyjąć
UIGestureRecognizerDelegate
protokół wewnątrzself
obiektu i wywołać poniższą metodę sprawdzania widoku. Wewnątrz tej metody sprawdź swój widoktouch.view
i zwróć odpowiednią wartość bool (Tak / Nie). Coś takiego:- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([touch.view isDescendantOfView:yourSubView]) { return NO; } return YES; }
Edycja: Proszę, sprawdź także odpowiedź @ Ian!
Szybki 5
// MARK: UIGestureRecognizerDelegate methods, You need to set the delegate of the recognizer func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { if touch.view?.isDescendant(of: tableView) == true { return false } return true }
źródło
-[UIGestureRecognizer requireGestureRecognizerToFail:]
ale może to zadziałać bez ichif
test się nie powiedzie, Twoja implementacja nie zwróci wartości BOOL; dla właściwego stylu zwraca TAK po bloku if (użycie{ }
) lub welse
gałęzi. Jednak dzięki, oszczędziłem trochę czytania.Innym podejściem jest po prostu porównanie, czy widok dotyku jest widokiem gestów, ponieważ potomkowie nie przejdą tego warunku. Ładny, prosty jednolinijkowy:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return touch.view == gestureRecognizer.view }
źródło
A dla wariantu Swift:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { if touch.view.isDescendantOfView(yourSubView){ return false } return true }
Warto wiedzieć,
isDescendantOfView
zwracaBoolean
wartość wskazującą, czy odbiornik jest podziałem danego widoku, czy identycznym z tym widokiem.źródło
W Swift 5 i iOS 12
UIGestureRecognizerDelegate
ma metodę o nazwiegestureRecognizer(_:shouldReceive:)
.gestureRecognizer(_:shouldReceive:)
posiada następującą deklarację:optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
Pełny kod poniżej przedstawia możliwą implementację dla
gestureRecognizer(_:shouldReceive:)
. W przypadku tego kodu stuknięcie w podwidokViewController
widoku (w tymimageView
) nie wyzwoliprintHello(_:)
metody.import UIKit class ViewController: UIViewController, UIGestureRecognizerDelegate { override func viewDidLoad() { super.viewDidLoad() let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(printHello)) tapGestureRecognizer.delegate = self view.addGestureRecognizer(tapGestureRecognizer) let imageView = UIImageView(image: UIImage(named: "icon")!) imageView.frame = CGRect(x: 50, y: 50, width: 100, height: 100) view.addSubview(imageView) // ⚠️ Enable user interaction for imageView so that it can participate to touch events. // Otherwise, taps on imageView will be forwarded to its superview and managed by it. imageView.isUserInteractionEnabled = true } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { // Prevent subviews of a specific view to send touch events to the view's gesture recognizers. if let touchedView = touch.view, let gestureView = gestureRecognizer.view, touchedView.isDescendant(of: gestureView), touchedView !== gestureView { return false } return true } @objc func printHello(_ sender: UITapGestureRecognizer) { print("Hello") } }
Alternatywną implementacją
gestureRecognizer(_:shouldReceive:)
może być:func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return gestureRecognizer.view === touch.view }
Należy jednak pamiętać, że ten alternatywny kod nie sprawdza, czy
touch.view
jest to podwidokgestureRecognizer.view
.źródło
Kompletne szybkie rozwiązanie (delegat musi być zaimplementowany ORAZ ustawiony dla aparatów rozpoznających):
class MyViewController: UIViewController UIGestureRecognizerDelegate { override func viewDidLoad() { let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(onBaseTapOnly)) doubleTapRecognizer.numberOfTapsRequired = 2 doubleTapRecognizer.delegate = self self.view.addGestureRecognizer(doubleTapRecognizer) } func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { if touch.view.isDescendantOfView(self.view){ return false } return true } func onBaseTapOnly(sender: UITapGestureRecognizer) { if sender.state == .Ended { //react to tap } } }
źródło
Wariant wykorzystujący CGPoint you touch (SWIFT 4.0)
class MyViewController: UIViewController, UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { // Get the location in CGPoint let location = touch.location(in: nil) // Check if location is inside the view to avoid if viewToAvoid.frame.contains(location) { return false } return true } }
źródło
Wyczyść Swift sposób
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return touch.view == self.view }
źródło
Zwróć uwagę, że interfejs API GestRecognizer zmienił się na:
gestRecognizer (_: shouldReceive :)
Zwróć szczególną uwagę na wskaźnik podkreślenia (pominięcia) dla zewnętrznej etykiety pierwszego parametru.
Korzystając z wielu przykładów podanych powyżej, nie otrzymałem wydarzenia. Poniżej znajduje się przykład, który działa dla aktualnych wersji Swift (3+).
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { var shouldReceive = false if let clickedView = touch.view { if clickedView == self.view { shouldReceive = true; } } return shouldReceive }
źródło
Plus powyższe rozwiązania, nie zapomnij sprawdzić
User Interaction Enabled
swojego podglądu.źródło
Musiałem zapobiec gestowi w widoku dziecka. Jedyne, co zadziałało, to zezwolenie i zachowanie pierwszego widoku oraz zapobieganie gestom we wszystkich następnych widokach:
var gestureView: UIView? = nil func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { if (gestureView == nil || gestureView == touch.view){ gestureView = touch.view return true } return false }
źródło
Swift 4:
touch.view
jest teraz opcjonalne, więc na podstawie odpowiedzi @ Antoine:func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { if let touchedView = touch.view, touchedView.isDescendant(of: deductibleBackgroundView) { return false } return true }
źródło
Jeśli nie chcesz, aby „rozpoznawanie podwójnego dotknięcia” powodowało konflikt z przyciskami i / lub innymi kontrolkami, możesz ustawić
self
jakoUIGestureRecognizerDelegate
i zaimplementować:func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return !(touch.view is UIControl) }
źródło