Huvudpunkter
UIGestureRecognizer — en abstrakt basklass i UIKit som delar upp gestigenkänningsprocessen i separata objekt. Varje underklass ansvarar för en gesttyp: UITapGestureRecognizer — för tap med ett visst antal fingrar, UISwipeGestureRecognizer — för svep i en given riktning. Utvecklaren lägger till igenkännaren på UIView via metoden addGestureRecognizer(:), och UIKit spårar automatiskt beröringar, uppdaterar tillståndet och anropar åtgärden vid igenkänning.
Innan UIGestureRecognizer kom (iOS 3.2, 2010) överskrev utvecklare UIResponder-metoderna — touchesBegan, touchesMoved, touchesEnded — och analyserade manuellt beröringarnas bana. Detta ledde till kodduplicering och fel vid bearbetning av samtidiga beröringar. Apple kapslade in denna logik i UIGestureRecognizer och lade till stöd för multitouch, annullering av gester och samtidig funktion av flera igenkännare på en vy.
Enligt WWDC-sessioner bearbetar Gesture Recognizer upp till 11 samtidiga beröringar på iPad och 5 på iPhone. På IT Sectr använder vi UIGestureRecognizer som standardsättet för att hantera användarinmatning i alla UIKit-projekt — detta har eliminerat buggar relaterade till manuell spårning av touchesBegan.
Varje UIGestureRecognizer går igenom 7 möjliga tillstånd, definierade i enumet UIGestureRecognizer.State. Dessa tillstånd reflekterar igenkänningslivscykeln: från detektering av beröring till slutförande eller annullering av gesten. Att förstå tillstånden är avgörande för att implementera anpassade igenkännare och felsöka konflikter.
| Tillstånd | Betydelse | När uppstår |
|---|---|---|
| .possible | Initialt tillstånd, gesten har inte identifierats än | Omedelbart efter tillägg till vyn |
| .began | Gesten har identifierats och börjat utföras | Vid första fingerrörelsen för pan/longPress |
| .changed | Gestparametrar har ändrats (koordinater, vinkel) | Vid varje fingerrörelse |
| .ended | Användaren har lyft fingret, gesten slutförd | Vid touchesEnded |
| .cancelled | Gesten avbruten av systemet (inkommande samtal, orienteringsändring) | Vid touchesCancelled |
| .failed | Gesten inte identifierad enligt villkoren | Vid touchesCancelled utan identifiering |
| .recognized | Synonym för .ended; gesten har identifierats framgångsrikt | Samma som .ended |
Diskreta gester (tap, swipe) går från .possible direkt till .ended eller .failed. Kontinuerliga gester (pan, pinch, rotation, longPress) går igenom .possible → .began → .changed (flera gånger) → .ended. I åtgärdsmetoden, kontrollera gestureRecognizer.state — detta gör det möjligt att skilja mellan början, förändring och slut av gesten.
UIKit tillhandahåller 7 inbyggda underklasser av UIGestureRecognizer, som täcker de flesta interaktionsscenarier. Varje underklass har specifika inställningar: numberOfTapsRequired för tap, direction för svep, minimumPressDuration för lång tryckning.
För anpassade gester (t.ex. ritning av sicksack) skapas en underklass av UIGestureRecognizer med överskridning av metoderna touchesBegan, touchesMoved, touchesEnded och uppdatering av tillstånd. Apple rekommenderar att använda inbyggda klasser där det är möjligt — de är optimerade och interagerar korrekt med varandra.
När flera UIGestureRecognizer används på en UIView (t.ex. tap och double-tap), uppstår en igenkänningskonflikt: vid dubbeltap aktiveras först den enkla tapen. Som lösning tillhandahåller Apple metoden require(toFail:), som fördröjer igenkänningen av en gest tills den andra misslyckas.
Mekanismen fungerar så här: genom att anropa tapRecognizer.require(toFail: doubleTapRecognizer) anger du att tapRecogniser övergår till tillståndet .recognized först efter att doubleTapRecogniser har avslutats i .failed. Detta lägger till en fördröjning på ~0,3 sekunder före utförandet av den enkla tapen — användaren trycker två gånger och den första tapen ignoreras. En alternativ metod — delegaten UIGestureRecognizerDelegate med metoden gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), som tillåter samtidig igenkänning (t.ex. pan + pinch för en karta).
Enligt WWDC 2020 är cirka 15% av buggarna i UIKit-appar relaterade till felaktig konfiguration av gestkonflikter. På IT Sectr har vi standardiserat tillvägagångssättet: för varje skärm skapas ett gestschema med require(toFail:)-prioriteter — detta har helt eliminerat buggar med dubbelaktivering av taps.
Lägger till en hanterare för enkel tap på UIImageView. Vid tap ändrar bilden sin genomskinlighet — det enklaste exemplet som visar bindning av en gest till en vy.
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
}
}
}
Viktig punkt: isUserInteractionEnabled på UIImageView är som standard false — utan denna flagga kommer Gesture Recognizer inte att ta emot beröringar. För UIView och UIButton är flaggan som standard aktiverad. Åtgärdsmetoden tar emot en UITapGestureRecognizer-parameter genom vilken location(in:) kan erhållas för att bestämma tapens koordinater.
Implementerar svep åt vänster för att återgå till föregående skärm. Demonstrerar konfiguration av riktning och bindning av gesten till kontrollerns rotvy.
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 — en diskret gest: den övergår till .recognised omedelbart efter identifiering, utan mellanliggande .changed. Därför behöver tillståndet inte kontrolleras i åtgärden — gesten antingen identifieras (åtgärden anropas) eller inte. Egenskapen direction accepterar ett av fyra värden: .left, .right, .up, .down. För att stödja flera riktningar, skapa separata igenkännare för varje riktning.
Visar hur man konfigurerar enkel och dubbel tap på samma vy utan konflikt. Igenkännaren för dubbel tap har prioritet — den enkla tapen aktiveras endast om den dubbla tapen inte identifieras.
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")
}
}
Utan require(toFail:) anropas först handleSingleTap, sedan handleDoubleTap vid dubbeltap — detta förstör användarupplevelsen. Med require(toFail:) väntar den enkla tapen ~0,3 sekunder för att försäkra sig om att den andra tapen inte följer. På IT Sectr används detta mönster i bildredigerare och gallerier, där dubbeltap zoomar in och enkel tap väljer ett element.
Vanliga frågor
Ja, UIView stöder flera UIGestureRecognizer samtidigt. För att lösa konflikter, använd metoden require(toFail:), som anger ordningen för igenkänning. För parallell funktion av gester (t.ex. pan + pinch på en karta) implementera delegaten gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), som returnerar true.
UIGestureRecognizer — en högnivåabstraktion som automatiskt identifierar beröringsmönster och hanterar tillstånd. touchesBegan — en lågnivåmetod i UIResponder som kräver manuell spårning av koordinater, timing och annullering av beröringar. Gesture Recognizer är enklare, mer pålitlig och att föredra för standardgester; touchesBegan är bara motiverad för anpassad grafik.
I inbyggt SwiftUI används modifierare: onTapGesture, onLongPressGesture, DragGesture, MagnificationGesture, RotationGesture. Dessa är deklarativa motsvarigheter till UIGestureRecognizer, integrerade i SwiftUI-hierarkin. Vid behov kan en UIKit-igenkännare lindas in via UIViewRepresentable, men Apple rekommenderar att använda inbyggda SwiftUI-gester.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också