Mga pangunahing punto
UIGestureRecognizer — isang abstract na base class sa UIKit na nagde-decompose ng proseso ng pagkilala ng kilos sa magkakahiwalay na bagay. Bawat subclass ay responsable para sa isang uri ng kilos: UITapGestureRecognizer — para sa tap na may tiyak na bilang ng mga daliri, UISwipeGestureRecognizer — para sa swipe sa isang tiyak na direksyon. Ang developer ay nagdaragdag ng tagakilala sa UIView sa pamamagitan ng pamamaraang addGestureRecognizer(:), at awtomatikong sinusubaybayan ng UIKit ang mga pagpindot, ina-update ang estado, at tinatawagan ang aksyon sa pagkilala.
Bago ang pagdating ng UIGestureRecognizer (iOS 3.2, 2010), ang mga developer ay nag-o-override ng mga pamamaraan ng UIResponder — touchesBegan, touchesMoved, touchesEnded — at manu-manong sinusuri ang trajectory ng mga pagpindot. Ito ay humantong sa pagdoble ng code at mga error sa pagproseso ng sabay-sabay na pagpindot. In-encapsulate ng Apple ang lohika na ito sa UIGestureRecognizer, nagdagdag ng suporta para sa multitouch, pagkansela ng mga kilos, at sabay-sabay na pagtatrabaho ng maraming tagakilala sa isang view.
Ayon sa mga sesyon ng WWDC, pinoproseso ng Gesture Recognizer ang hanggang 11 sabay-sabay na pagpindot sa iPad at 5 sa iPhone. Sa IT Sectr, ginagamit namin ang UIGestureRecognizer bilang karaniwang paraan ng pagproseso ng input ng gumagamit sa lahat ng UIKit na proyekto — inalis nito ang mga bug na may kaugnayan sa manu-manong pagsubaybay ng touchesBegan.
Bawat UIGestureRecognizer ay dumadaan sa 7 posibleng estado, na tinukoy sa enum na UIGestureRecognizer.State. Ang mga estadong ito ay sumasalamin sa lifecycle ng pagkilala: mula sa pagtuklas ng pagpindot hanggang sa pagkumpleto o pagkansela ng kilos. Ang pag-unawa sa mga estado ay kritikal para sa pagpapatupad ng mga custom na tagakilala at pag-debug ng mga salungatan.
| Estado | Kahulugan | Kailan nagaganap |
|---|---|---|
| .possible | Paunang estado, hindi pa nakikilala ang kilos | Kaagad pagkatapos idagdag sa view |
| .began | Nakilala ang kilos at nagsimulang isagawa | Sa unang galaw ng daliri para sa pan/longPress |
| .changed | Nagbago ang mga parameter ng kilos (coordinate, anggulo) | Sa bawat galaw ng daliri |
| .ended | Inalis ng gumagamit ang daliri, natapos ang kilos | Sa touchesEnded |
| .cancelled | Ang kilos ay naantala ng system (papasok na tawag, pagbabago ng oryentasyon) | Sa touchesCancelled |
| .failed | Hindi nakilala ang kilos ayon sa mga kondisyon | Sa touchesCancelled na walang pagkilala |
| .recognized | Kasingkahulugan ng .ended; matagumpay na nakilala ang kilos | Kapareho ng .ended |
Ang mga discrete na kilos (tap, swipe) ay lumilipat mula .possible direkta sa .ended o .failed. Ang mga tuluy-tuloy na kilos (pan, pinch, rotation, longPress) ay dumadaan sa .possible → .began → .changed (paulit-ulit) → .ended. Sa action method, suriin ang gestureRecognizer.state — pinapayagan nito na makilala ang simula, pagbabago, at pagtatapos ng kilos.
Ang UIKit ay nagbibigay ng 7 built-in na subclass ng UIGestureRecognizer, na sumasaklaw sa karamihan ng mga senaryo ng interaksyon. Bawat subclass ay may mga tiyak na setting: numberOfTapsRequired para sa tap, direction para sa swipe, minimumPressDuration para sa matagal na pindot.
Para sa mga custom na kilos (halimbawa, pagguhit ng zigzag), gumawa ng subclass ng UIGestureRecognizer na may override ng mga pamamaraang touchesBegan, touchesMoved, touchesEnded at pag-update ng estado. Inirerekomenda ng Apple na gamitin ang mga built-in na klase kung saan posible — ang mga ito ay na-optimize at wastong nakikipag-ugnayan sa isa't isa.
Kapag maraming UIGestureRecognizer ang ginagamit sa isang UIView (halimbawa, tap at double-tap), nagaganap ang isang salungatan sa pagkilala: sa dobleng tap, unang nag-trigger ang isahang tap. Para sa solusyon, nagbibigay ang Apple ng pamamaraang require(toFail:), na nagpapabagal sa pagkilala ng isang kilos hanggang sa mabigo ang isa pa.
Gumagana ang mekanismo tulad sumusunod: sa pagtawag ng tapRecognizer.require(toFail: doubleTapRecognizer), tinutukoy mo na ang tapRecogniser ay lilipat sa estadong .recognized pagkatapos lamang matapos ang doubleTapRecogniser sa .failed. Nagdaragdag ito ng pagkaantala na ~0.3 segundo bago isagawa ang isahang tap — dalawang beses pumipindot ang gumagamit, at ang unang tap ay hindi pinapansin. Ang alternatibong pamamaraan — ang delegate na UIGestureRecognizerDelegate na may pamamaraang gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), na nagpapahintulot ng sabay-sabay na pagkilala (halimbawa, pan + pinch para sa mapa).
Ayon sa WWDC 2020, humigit-kumulang 15% ng mga bug sa mga UIKit app ay may kaugnayan sa maling configuration ng mga salungatan ng kilos. Sa IT Sectr, na-standardize namin ang diskarte: para sa bawat screen, ginagawa ang isang scheme ng kilos na may mga priyoridad ng require(toFail:) — ganap nitong inalis ang mga bug na may dobleng pag-trigger ng mga tap.
Nagdaragdag ng handler ng isahang tap sa UIImageView. Kapag na-tap, binabago ng larawan ang transparency — ang pinakasimpleng halimbawa na nagpapakita ng pag-ugnay ng kilos sa view.
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
}
}
}
Mahalagang punto: ang isUserInteractionEnabled sa UIImageView ay default na false — kung wala ang flag na ito, hindi makakatanggap ng mga pagpindot ang Gesture Recognizer. Para sa UIView at UIButton, ang flag ay default na naka-enable. Ang action method ay tumatanggap ng parameter na UITapGestureRecognizer kung saan maaaring makuha ang location(in:) para sa pagtukoy ng mga coordinate ng tap.
Nagpapatupad ng swipe sa kaliwa para bumalik sa nakaraang screen. Nagpapakita ng configuration ng direksyon at pag-ugnay ng kilos sa root view ng 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)
}
}
Ang UISwipeGestureRecognizer — ay isang discrete na kilos: lumilipat ito sa .recognised kaagad pagkatapos makilala, nang walang intermediate na .changed. Kaya naman sa aksyon hindi na kailangang suriin ang estado — ang kilos ay maaaring makilala (tatawagin ang aksyon) o hindi. Ang property na direction ay tumatanggap ng isa sa apat na halaga: .left, .right, .up, .down. Para suportahan ang maraming direksyon, gumawa ng hiwalay na mga tagakilala para sa bawat isa.
Nagpapakita kung paano i-configure ang isahan at dobleng tap sa parehong view nang walang salungatan. Ang tagakilala ng dobleng tap ay may priyoridad — ang isahang tap ay nag-trigger lamang kung ang dobleng tap ay hindi nakilala.
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")
}
}
Kung walang require(toFail:), sa dobleng tap, unang tatawagin ang handleSingleTap, pagkatapos ang handleDoubleTap — sinisira nito ang UX. Sa require(toFail:), ang isahang tap ay naghihintay ng ~0.3 segundo upang matiyak na hindi susunod ang pangalawang tap. Sa IT Sectr, ang pattern na ito ay ginagamit sa mga editor ng larawan at gallery, kung saan ang dobleng tap ay nag-zoom in, at ang isahang tap ay pumipili ng elemento.
Mga madalas itanong
Oo, sinusuportahan ng UIView ang maraming UIGestureRecognizer nang sabay-sabay. Para sa paglutas ng mga salungatan, gamitin ang pamamaraang require(toFail:), na nagtatakda ng pagkakasunod-sunod ng pagkilala. Para sa parallel na pagtatrabaho ng mga kilos (halimbawa, pan + pinch sa mapa), ipatupad ang delegate na gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), na nagbabalik ng true.
UIGestureRecognizer — isang mataas na antas na abstraksyon na awtomatikong kumikilala ng mga pattern ng pagpindot at namamahala ng mga estado. Ang touchesBegan — ay isang mababang antas na pamamaraan ng UIResponder na nangangailangan ng manu-manong pagsubaybay ng mga coordinate, timing, at pagkansela ng mga pagpindot. Ang Gesture Recognizer ay mas simple, mas maaasahan, at mas mainam para sa mga karaniwang kilos; ang touchesBegan ay makatwiran lamang para sa custom na graphics.
Sa native na SwiftUI, ginagamit ang mga modifier: onTapGesture, onLongPressGesture, DragGesture, MagnificationGesture, RotationGesture. Ang mga ito ay deklaratibong katapat ng UIGestureRecognizer, na isinama sa hierarchy ng SwiftUI. Kung kinakailangan, maaaring balutin ang UIKit tagakilala sa pamamagitan ng UIViewRepresentable, ngunit inirerekomenda ng Apple ang paggamit ng native na SwiftUI na mga kilos.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din