Belangrijkste punten
UIGestureRecognizer — een abstracte basisklasse in UIKit die het herkenningsproces van gebaren opsplitst in afzonderlijke objecten. Elke subklasse is verantwoordelijk voor één type gebaar: UITapGestureRecognizer — voor tap met een bepaald aantal vingers, UISwipeGestureRecognizer — voor swipe in een bepaalde richting. De ontwikkelaar voegt de herkenner toe aan UIView via de methode addGestureRecognizer(:), en UIKit volgt automatisch aanrakingen, werkt de status bij en roept de actie aan bij herkenning.
Vóór de komst van UIGestureRecognizer (iOS 3.2, 2010) overschreven ontwikkelaars de UIResponder-methoden — touchesBegan, touchesMoved, touchesEnded — en analyseerden ze handmatig het traject van aanrakingen. Dit leidde tot code-duplicatie en fouten bij het verwerken van gelijktijdige aanrakingen. Apple heeft deze logica ingekapseld in UIGestureRecognizer en ondersteuning toegevoegd voor multitouch, het annuleren van gebaren en gelijktijdig werken van meerdere herkenners op één weergave.
Volgens WWDC-sessies verwerkt Gesture Recognizer tot 11 gelijktijdige aanrakingen op iPad en 5 op iPhone. Bij IT Sectr gebruiken we UIGestureRecognizer als standaard manier om gebruikersinvoer te verwerken in alle UIKit-projecten — dit heeft bugs gerelateerd aan handmatig bijhouden van touchesBegan geëlimineerd.
Elke UIGestureRecognizer doorloopt 7 mogelijke statussen, gedefinieerd in de enum UIGestureRecognizer.State. Deze statussen weerspiegelen de levenscyclus van herkenning: van het detecteren van aanraking tot het voltooien of annuleren van het gebaar. Inzicht in de statussen is cruciaal voor het implementeren van aangepaste herkenners en het debuggen van conflicten.
| Status | Betekenis | Wanneer ontstaat |
|---|---|---|
| .possible | Beginstatus, gebaar nog niet herkend | Direct na toevoegen aan weergave |
| .began | Gebaar herkend en begonnen met uitvoeren | Bij eerste vingerbeweging voor pan/longPress |
| .changed | Parameters van gebaar gewijzigd (coördinaten, hoek) | Bij elke vingerbeweging |
| .ended | Gebruiker heeft vinger opgetild, gebaar voltooid | Bij touchesEnded |
| .cancelled | Gebaar onderbroken door systeem (inkomende oproep, oriëntatiewijziging) | Bij touchesCancelled |
| .failed | Gebaar niet herkend volgens voorwaarden | Bij touchesCancelled zonder herkenning |
| .recognized | Synoniem voor .ended; gebaar succesvol herkend | Hetzelfde als .ended |
Discrete gebaren (tap, swipe) gaan van .possible direct naar .ended of .failed. Continue gebaren (pan, pinch, rotation, longPress) doorlopen .possible → .began → .changed (herhaaldelijk) → .ended. Controleer in de action-methode gestureRecognizer.state — dit maakt het mogelijk onderscheid te maken tussen begin, wijziging en einde van het gebaar.
UIKit biedt 7 ingebouwde subklassen van UIGestureRecognizer, die de meeste interactiescenario's dekken. Elke subklasse heeft specifieke instellingen: numberOfTapsRequired voor tap, direction voor swipe, minimumPressDuration voor lang indrukken.
Voor aangepaste gebaren (bijvoorbeeld het tekenen van een zigzag) wordt een subklasse van UIGestureRecognizer gemaakt met overschrijving van de methoden touchesBegan, touchesMoved, touchesEnded en bijwerken van de status. Apple raadt aan waar mogelijk ingebouwde klassen te gebruiken — ze zijn geoptimaliseerd en werken correct met elkaar samen.
Wanneer op één UIView meerdere UIGestureRecognizer worden gebruikt (bijv. tap en double-tap), ontstaat er een herkenningsconflict: bij dubbeltap wordt eerst de enkele tap geactiveerd. Voor de oplossing biedt Apple de methode require(toFail:), die de herkenning van het ene gebaar uitstelt totdat het andere mislukt.
Het mechanisme werkt als volgt: door tapRecognizer.require(toFail: doubleTapRecognizer) aan te roepen, geeft u aan dat tapRecogniser pas naar de status .recognized gaat nadat doubleTapRecogniser is geëindigd in .failed. Dit voegt een vertraging van ~0,3 seconden toe vóór uitvoering van de enkele tap — de gebruiker tikt twee keer en de eerste tap wordt genegeerd. Een alternatieve methode — de delegate UIGestureRecognizerDelegate met de methode gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), die gelijktijdige herkenning toestaat (bijv. pan + pinch voor een kaart).
Volgens WWDC 2020 is ongeveer 15% van de bugs in UIKit-apps gerelateerd aan onjuiste configuratie van gebarenconflicten. Bij IT Sectr hebben we de aanpak gestandaardiseerd: voor elk scherm wordt een gebarenschema gemaakt met require(toFail:)-prioriteiten — dit heeft bugs met dubbel geactiveerde taps volledig geëlimineerd.
Voegt een handler voor enkele tap toe op UIImageView. Bij een tap verandert de afbeelding van doorzichtigheid — het eenvoudigste voorbeeld dat het koppelen van een gebaar aan een weergave laat zien.
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
}
}
}
Belangrijk punt: isUserInteractionEnabled op UIImageView is standaard false — zonder deze vlag ontvangt Gesture Recognizer geen aanrakingen. Voor UIView en UIButton is de vlag standaard ingeschakeld. De action-methode accepteert een UITapGestureRecognizer-parameter waarmee location(in:) kan worden verkregen om de coördinaten van de tap te bepalen.
Implementeert een swipe naar links om terug te keren naar het vorige scherm. Demonstreert het instellen van de richting en het koppelen van het gebaar aan de root-weergave van de controller.
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 — een discreet gebaar: het gaat onmiddellijk na herkenning naar .recognised, zonder tussenliggende .changed. Daarom hoeft in de actie de status niet te worden gecontroleerd — het gebaar wordt ofwel herkend (actie wordt aangeroepen) of niet. De eigenschap direction accepteert een van vier waarden: .left, .right, .up, .down. Maak voor ondersteuning van meerdere richtingen aparte herkenners voor elke richting.
Laat zien hoe u enkele en dubbele tap op dezelfde weergave configureert zonder conflict. De herkenner van de dubbele tap heeft prioriteit — de enkele tap wordt alleen geactiveerd als de dubbele tap niet is herkend.
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")
}
}
Zonder require(toFail:) wordt bij dubbeltap eerst handleSingleTap aangeroepen, daarna handleDoubleTap — dit verpest de UX. Met require(toFail:) wacht de enkele tap ~0,3 seconden om er zeker van te zijn dat de tweede tap niet volgt. Bij IT Sectr wordt dit patroon gebruikt in beeldbewerkers en galerijen, waar dubbeltap inzoomt en enkele tap een element selecteert.
Veelgestelde vragen
Ja, UIView ondersteunt meerdere UIGestureRecognizer tegelijkertijd. Gebruik voor het oplossen van conflicten de methode require(toFail:), die de herkenningsvolgorde bepaalt. Voor parallelle werking van gebaren (bijv. pan + pinch op een kaart) implementeert u de delegate gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), die true retourneert.
UIGestureRecognizer — een abstractie op hoog niveau die aanraakpatronen automatisch herkent en statussen beheert. touchesBegan — een methode op laag niveau van UIResponder die handmatig bijhouden van coördinaten, timing en annuleren van aanrakingen vereist. Gesture Recognizer is eenvoudiger, betrouwbaarder en heeft de voorkeur voor standaard gebaren; touchesBegan is alleen gerechtvaardigd voor aangepaste grafische weergave.
In native SwiftUI worden modifiers gebruikt: onTapGesture, onLongPressGesture, DragGesture, MagnificationGesture, RotationGesture. Dit zijn declaratieve tegenhangers van UIGestureRecognizer, geïntegreerd in de SwiftUI-hiërarchie. Indien nodig kunt u een UIKit-herkenner inpakken via UIViewRepresentable, maar Apple raadt het gebruik van native SwiftUI-gebaren aan.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook