Poin utama
UIGestureRecognizer — kelas dasar abstrak di UIKit yang mendekomposisi proses pengenalan gestur menjadi objek terpisah. Setiap subkelas bertanggung jawab untuk satu jenis gestur: UITapGestureRecognizer — untuk tap dengan jumlah jari tertentu, UISwipeGestureRecognizer — untuk geser ke arah tertentu. Pengembang menambahkan pengenal ke UIView melalui metode addGestureRecognizer(:), dan UIKit secara otomatis melacak sentuhan, memperbarui status, dan memanggil aksi saat dikenali.
Sebelum munculnya UIGestureRecognizer (iOS 3.2, 2010), pengembang menimpa metode UIResponder — touchesBegan, touchesMoved, touchesEnded — dan menganalisis lintasan sentuhan secara manual. Ini menyebabkan duplikasi kode dan kesalahan dalam menangani sentuhan simultan. Apple mengenkapsulasi logika ini ke dalam UIGestureRecognizer, menambahkan dukungan untuk multitouch, pembatalan gestur, dan kerja simultan beberapa pengenal pada satu tampilan.
Menurut sesi WWDC, Gesture Recognizer memproses hingga 11 sentuhan simultan di iPad dan 5 di iPhone. Di IT Sectr, kami menggunakan UIGestureRecognizer sebagai cara standar untuk menangani masukan pengguna di semua proyek UIKit — ini menghilangkan bug terkait pelacakan manual touchesBegan.
Setiap UIGestureRecognizer melalui 7 status yang mungkin, didefinisikan dalam enum UIGestureRecognizer.State. Status ini mencerminkan siklus hidup pengenalan: dari deteksi sentuhan hingga penyelesaian atau pembatalan gestur. Memahami status sangat penting untuk mengimplementasikan pengenal kustom dan men-debug konflik.
| Status | Arti | Kapan terjadi |
|---|---|---|
| .possible | Status awal, gestur belum dikenali | Segera setelah ditambahkan ke tampilan |
| .began | Gestur dikenali dan mulai dijalankan | Pada gerakan jari pertama untuk pan/longPress |
| .changed | Parameter gestur berubah (koordinat, sudut) | Pada setiap gerakan jari |
| .ended | Pengguna mengangkat jari, gestur selesai | Saat touchesEnded |
| .cancelled | Gestur diinterupsi oleh sistem (panggilan masuk, perubahan orientasi) | Saat touchesCancelled |
| .failed | Gestur tidak dikenali sesuai kondisi | Saat touchesCancelled tanpa pengenalan |
| .recognized | Sinonim untuk .ended; gestur berhasil dikenali | Sama seperti .ended |
Gestur diskrit (tap, swipe) beralih dari .possible langsung ke .ended atau .failed. Gestur kontinu (pan, pinch, rotation, longPress) melalui .possible → .began → .changed (berulang) → .ended. Di metode aksi, periksa gestureRecognizer.state — ini memungkinkan membedakan awal, perubahan, dan akhir gestur.
UIKit menyediakan 7 subkelas bawaan UIGestureRecognizer, yang mencakup sebagian besar skenario interaksi. Setiap subkelas memiliki pengaturan khusus: numberOfTapsRequired untuk tap, direction untuk geser, minimumPressDuration untuk tekan lama.
Untuk gestur kustom (misalnya, menggambar zigzag), dibuat subkelas UIGestureRecognizer dengan menimpa metode touchesBegan, touchesMoved, touchesEnded dan memperbarui status. Apple merekomendasikan penggunaan kelas bawaan jika memungkinkan — kelas tersebut dioptimalkan dan berinteraksi dengan benar satu sama lain.
Ketika beberapa UIGestureRecognizer digunakan pada satu UIView (misalnya, tap dan double-tap), terjadi konflik pengenalan: pada tap ganda, tap tunggal terpicu terlebih dahulu. Untuk solusinya, Apple menyediakan metode require(toFail:), yang menunda pengenalan satu gestur sampai gestur lainnya gagal.
Mekanismenya bekerja sebagai berikut: dengan memanggil tapRecognizer.require(toFail: doubleTapRecognizer), Anda menentukan bahwa tapRecogniser akan beralih ke status .recognized hanya setelah doubleTapRecogniser selesai dalam .failed. Ini menambahkan penundaan ~0,3 detik sebelum eksekusi tap tunggal — pengguna mengetuk dua kali, dan tap pertama diabaikan. Metode alternatif — delegasi UIGestureRecognizerDelegate dengan metode gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), yang mengizinkan pengenalan simultan (misalnya, pan + pinch untuk peta).
Menurut WWDC 2020, sekitar 15% bug di aplikasi UIKit terkait dengan konfigurasi konflik gestur yang salah. Di IT Sectr, kami menstandarisasi pendekatan: untuk setiap layar, dibuat skema gestur dengan prioritas require(toFail:) — ini sepenuhnya menghilangkan bug dengan pemicuan ganda tap.
Menambahkan handler tap tunggal pada UIImageView. Saat diketuk, gambar mengubah transparansi — contoh paling sederhana yang menunjukkan pengikatan gestur ke tampilan.
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
}
}
}
Poin penting: isUserInteractionEnabled di UIImageView secara default adalah false — tanpa bendera ini, Gesture Recognizer tidak akan menerima sentuhan. Untuk UIView dan UIButton, bendera ini aktif secara default. Metode aksi menerima parameter UITapGestureRecognizer yang melaluinya location(in:) dapat diperoleh untuk menentukan koordinat tap.
Mengimplementasikan geser ke kiri untuk kembali ke layar sebelumnya. Mendemonstrasikan konfigurasi arah dan pengikatan gestur ke tampilan root 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 — gestur diskrit: ia beralih ke .recognised segera setelah dikenali, tanpa .changed perantara. Oleh karena itu, di aksi, status tidak perlu diperiksa — gestur dikenali (aksi dipanggil) atau tidak. Properti direction menerima salah satu dari empat nilai: .left, .right, .up, .down. Untuk mendukung beberapa arah, buat pengenal terpisah untuk setiap arah.
Menunjukkan cara mengonfigurasi tap tunggal dan ganda pada tampilan yang sama tanpa konflik. Pengenal tap ganda memiliki prioritas — tap tunggal hanya terpicu jika tap ganda tidak dikenali.
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")
}
}
Tanpa require(toFail:), pada tap ganda, handleSingleTap akan dipanggil terlebih dahulu, lalu handleDoubleTap — ini merusak UX. Dengan require(toFail:), tap tunggal menunggu ~0,3 detik untuk memastikan tap kedua tidak menyusul. Di IT Sectr, pola ini digunakan di editor gambar dan galeri, di mana tap ganda memperbesar, dan tap tunggal memilih elemen.
Pertanyaan yang sering diajukan
Ya, UIView mendukung beberapa UIGestureRecognizer secara simultan. Untuk menyelesaikan konflik, gunakan metode require(toFail:), yang menentukan urutan pengenalan. Untuk kerja paralel gestur (misalnya, pan + pinch pada peta), implementasikan delegasi gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), yang mengembalikan true.
UIGestureRecognizer — abstraksi tingkat tinggi yang secara otomatis mengenali pola sentuhan dan mengelola status. touchesBegan — metode tingkat rendah UIResponder yang memerlukan pelacakan manual koordinat, waktu, dan pembatalan sentuhan. Gesture Recognizer lebih sederhana, lebih andal, dan lebih disukai untuk gestur standar; touchesBagan hanya dibenarkan untuk grafik kustom.
Di SwiftUI asli, digunakan pengubah: onTapGesture, onLongPressGesture, DragGesture, MagnificationGesture, RotationGesture. Ini adalah padanan deklaratif dari UIGestureRecognizer, terintegrasi ke dalam hierarki SwiftUI. Jika perlu, Anda dapat membungkus pengenal UIKit melalui UIViewRepresentable, tetapi Apple merekomendasikan penggunaan gestur asli SwiftUI.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga