Wichtige Punkte
UIGestureRecognizer ist eine abstrakte Basisklasse in UIKit, die den Gestenerkennungsprozess in separate Objekte zerlegt. Jede Unterklasse behandelt einen Gestentyp: UITapGestureRecognizer behandelt einen Tap mit einer bestimmten Anzahl von Berührungen, UISwipeGestureRecognizer behandelt einen Wisch in eine bestimmte Richtung. Der Entwickler fügt den Recognizer über die Methode addGestureRecognizer(:) zu UIView hinzu, und UIKit verfolgt automatisch Berührungen, aktualisiert den Zustand und ruft bei Erkennung eine Aktion auf.
Vor UIGestureRecognizer (iOS 3.2, 2010) überschrieben Entwickler UIResponder-Methoden — touchesBegan, touchesMoved, touchesEnded — und analysierten manuell die Berührungsverläufe. Dies führte zu Code-Duplizierung und Fehlern bei der Verarbeitung gleichzeitiger Berührungen. Apple kapselte diese Logik in UIGestureRecognizer und fügte Unterstützung für Multitouch, Gestenabbruch und gleichzeitigen Betrieb mehrerer Recognizer auf einer View hinzu.
Laut WWDC-Sitzungen verarbeitet Gesture Recognizer bis zu 11 gleichzeitige Berührungen auf dem iPad und 5 auf dem iPhone. Bei IT Sectr verwenden wir UIGestureRecognizer als Standardmethode zur Behandlung von Benutzereingaben in allen UIKit-Projekten — dies beseitigte Fehler im Zusammenhang mit manueller touchesBegan-Verfolgung.
Jeder UIGestureRecognizer durchläuft 7 mögliche Zustände, die im Enum UIGestureRecognizer.State definiert sind. Diese Zustände spiegeln den Erkennungslebenszyklus wider: von der Berührungserkennung bis zum Abschluss oder Abbruch. Das Verständnis der Zustände ist entscheidend für die Implementierung benutzerdefinierter Recognizer und das Debuggen von Konflikten.
| Zustand | Bedeutung | Wann er auftritt |
|---|---|---|
| .possible | Anfangszustand, Geste noch nicht erkannt | Direkt nach dem Hinzufügen zu einer View |
| .began | Geste erkannt und beginnt ausgeführt zu werden | Bei erster Fingerbewegung für pan/longPress |
| .changed | Gestenparameter geändert (Koordinaten, Winkel) | Bei jeder Fingerbewegung |
| .ended | Benutzer hob Finger, Geste abgeschlossen | Bei touchesEnded |
| .cancelled | Geste durch System unterbrochen (Anruf, Ausrichtungsänderung) | Bei touchesCancelled |
| .failed | Geste gemäß Bedingungen nicht erkannt | Bei touchesCancelled ohne Erkennung |
| .recognized | Synonym für .ended; Geste erfolgreich erkannt | Gleiches wie .ended |
Diskrete Gesten (Tap, Swipe) wechseln von .possible direkt zu .ended oder .failed. Kontinuierliche Gesten (Pan, Pinch, Rotation, LongPress) durchlaufen .possible → .began → .changed (wiederholt) → .ended. In der Aktionsmethode prüfen Sie gestureRecognizer.state — dies ermöglicht die Unterscheidung von Beginn, Änderung und Ende einer Geste.
UIKit bietet 7 integrierte UIGestureRecognizer-Unterklassen, die die meisten Interaktionsszenarien abdecken. Jede Unterklasse hat spezifische Einstellungen: numberOfTapsRequired für Tap, direction für Swipe, minimumPressDuration für langes Drücken.
Für benutzerdefinierte Gesten (z. B. Zeichnen eines Zickzacks) wird eine UIGestureRecognizer-Unterklasse erstellt, die touchesBegan, touchesMoved, touchesEnded überschreibt und den Zustand aktualisiert. Apple empfiehlt, wo möglich integrierte Klassen zu verwenden — sie sind optimiert und interagieren korrekt miteinander.
Wenn mehrere UIGestureRecognizer auf einer UIView verwendet werden (z. B. Tap und Doppeltap), tritt ein Erkennungskonflikt auf: Bei einem Doppeltap feuert zuerst der einfache Tap. Apple stellt die Methode require(toFail:) zur Verfügung, die die Erkennung einer Geste verzögert, bis eine andere fehlschlägt.
Der Mechanismus funktioniert so: Durch Aufruf von tapRecognizer.require(toFail: doubleTapRecognizer) legen Sie fest, dass tapRecognizer nur dann in den Zustand .recognized übergeht, wenn doubleTapRecognizer in .failed endet. Dies fügt eine Verzögerung von ~0,3 Sekunden vor der Ausführung des einfachen Taps hinzu — der Benutzer tippt zweimal und der erste Tap wird ignoriert. Ein alternativer Ansatz ist der Delegat UIGestureRecognizerDelegate mit der Methode gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), die gleichzeitige Erkennung erlaubt (z. B. Pan + Pinch für eine Karte).
Laut WWDC 2020 hängen etwa 15% der Fehler in UIKit-Anwendungen mit falscher Konfiguration von Gestenkonflikten zusammen. Bei IT Sectr haben wir den Ansatz standardisiert: Jeder Bildschirm hat ein Gestenschema mit require(toFail:)-Prioritäten — dies beseitigte Doppeltap-Fehler vollständig.
Fügt einen Einfach-Tap-Handler zu UIImageView hinzu. Bei Berührung ändert sich die Deckkraft des Bildes — ein einfaches Beispiel, das die Bindung einer Geste an eine View zeigt.
import UIKit
class ImageViewController: UIViewController {
@IBOutlet private var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(
target: self,
action: #selector(handleTap(_:))
)
tap.numberOfTapsRequired = 1
imageView.addGestureRecognizer(tap)
imageView.isUserInteractionEnabled = true
}
@objc private func handleTap(_: UITapGestureRecognizer) {
UIView.animate(withDuration: 0.2) {
self.imageView.alpha = self.imageView.alpha == 1.0 ? 0.5 : 1.0
}
}
}
Wichtiger Punkt: isUserInteractionEnabled auf UIImageView ist standardmäßig false — ohne dieses Flag erhält Gesture Recognizer keine Berührungen. Bei UIView und UIButton ist dieses Flag standardmäßig aktiviert. Die Aktionsmethode akzeptiert einen UITapGestureRecognizer-Parameter, über den location(in:) zur Bestimmung der Tap-Koordinaten abgerufen werden kann.
Implementiert einen Wisch nach links, um zum vorherigen Bildschirm zurückzukehren. Zeigt die Richtungskonfiguration und die Bindung der Geste an die Root-View des Controllers.
import UIKit
class DetailViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swipeLeft = UISwipeGestureRecognizer(
target: self,
action: #selector(handleSwipe(_:))
)
swipeLeft.direction = .left
view.addGestureRecognizer(swipeLeft)
}
@objc private func handleSwipe(_: UISwipeGestureRecognizer) {
navigationController?.popViewController(animated: true)
}
}
UISwipeGestureRecognizer ist eine diskrete Geste: Sie wechselt sofort nach Erkennung in .recognized, ohne zwischengeschaltete .changed-Zustände. Daher muss der Zustand in der Aktion nicht geprüft werden — die Geste wird entweder erkannt (Aktion feuert) oder nicht. Die Eigenschaft direction akzeptiert einen von vier Werten: .left, .right, .up, .down. Zur Unterstützung mehrerer Richtungen erstellen Sie separate Recognizer für jede.
Zeigt, wie Einfach- und Doppeltap auf einer View ohne Konflikt konfiguriert werden. Der Doppeltap-Recognizer hat Priorität — der einfache Tap feuert nur, wenn der Doppeltap nicht erkannt wird.
import UIKit
class TapViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let singleTap = UITapGestureRecognizer(
target: self,
action: #selector(handleSingleTap)
)
singleTap.numberOfTapsRequired = 1
let doubleTap = UITapGestureRecognizer(
target: self,
action: #selector(handleDoubleTap)
)
doubleTap.numberOfTapsRequired = 2
singleTap.require(toFail: doubleTap)
view.addGestureRecognizer(singleTap)
view.addGestureRecognizer(doubleTap)
}
@objc private func handleSingleTap() {
print("Single tap — after 0.3s delay")
}
@objc private func handleDoubleTap() {
print("Double tap — instant")
}
}
Ohne require(toFail:) feuert bei einem Doppeltap zuerst handleSingleTap, dann handleDoubleTap — dies beeinträchtigt die UX. Mit require(toFail:) wartet der einfache Tap ~0,3 Sekunden, um sicherzustellen, dass kein zweiter Tap folgt. Bei IT Sectr wird dieses Muster in Bildeditoren und Galerien verwendet, wo ein Doppeltap zoomt und ein einfacher Tap ein Element auswählt.
Häufig gestellte Fragen
Ja, UIView unterstützt mehrere UIGestureRecognizer-Instanzen gleichzeitig. Zur Konfliktlösung verwenden Sie die Methode require(toFail:), die die Erkennungsreihenfolge festlegt. Für parallele Gestenoperationen (z. B. pan + pinch auf einer Karte) implementieren Sie die Delegatmethode gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), die true zurückgibt.
UIGestureRecognizer ist eine hochrangige Abstraktion, die Berührungsmuster automatisch erkennt und Zustände verwaltet. touchesBegan ist eine niedrige UIResponder-Methode, die manuelle Koordinatenverfolgung, Timing und Berührungsabbruch erfordert. Gesture Recognizer ist einfacher, zuverlässiger und für Standardgesten vorzuziehen; touchesBegan ist nur für benutzerdefinierte Grafiken gerechtfertigt.
Natives SwiftUI verwendet Modifikatoren: onTapGesture, onLongPressGesture, DragGesture, MagnificationGesture, RotationGesture. Dies sind deklarative Analoga von UIGestureRecognizer, die in die SwiftUI-Hierarchie integriert sind. Bei Bedarf kann ein UIKit-Recognizer über UIViewRepresentable eingebunden werden, aber Apple empfiehlt die Verwendung nativer SwiftUI-Gesten.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch