Gesture Recognizer — шта је то, обрада додира у iOS

Аутор: IT Sectr Објављено: 2026-02-27 Време читања: 8 мин
Gesture Recognizer — апстракција у UIKit која претвара низ додира корисника у препознати гест: тап, превлачење, дуго притискање, штипање или окретање. Уместо ручног праћења координата у методама touchesBegan/touchesMoved, програмер додаје готов објекат UIGestureRecognizer на UIView и имплементира action метод. Према Apple Developer Documentation, UIGestureRecognizer подржава 7 уграђених подкласа које покривају 95% типичних гестова у мобилним апликацијама.

Главне тачке

  • UIGestureRecognizer — апстрактна класа UIKit за препознавање образаца додира: тапова, превлачења, штипања, окретања и дугих притисака.
  • 7 уграђених подкласа: UITapGestureRecognizer, UISwipeGestureRecognizer, UIPinchGestureRecognizer, UIRotationGestureRecognizer, UILongPressGestureRecognizer, UIPanGestureRecognizer, UIScreenEdgePanGestureRecognizer.
  • Сваки препознавач има стање (possible, began, changed, ended, cancelled, failed) које се ажурира током покрета прстију.
  • За решавање сукоба између гестова користи се метод require(toFail:), који поставља приоритет препознавања.
  • Gesture Recognizer ради са UIKit и UIViewRepresentable у SwiftUI, али у изворном SwiftUI примењују се модификатори гестова.

Шта је Gesture Recognizer?

UIGestureRecognizer — апстрактна основна класа у UIKit која декомпонује процес препознавања гестова у засебне објекте. Свака подкласа је одговорна за једну врсту геста: UITapGestureRecognizer — за тап одређеног броја прстију, UISwipeGestureRecognizer — за превлачење у задатом правцу. Програмер додаје препознавач на UIView путем метода addGestureRecognizer(:), и UIKit аутоматски прати додире, ажурира стање и позива акцију при препознавању.

Пре појаве UIGestureRecognizer (iOS 3.2, 2010) програмери су преписивали методе UIResponder — touchesBegan, touchesMoved, touchesEnded — и ручно анализирали путању додира. То је доводило до дуплирања кода и грешака при обради истовремених додира. Apple је инкапсулирао ову логику у UIGestureRecognizer, додавши подршку за мултитач, отказивање гестова и истовремени рад више препознавача на истом приказу.

Према WWDC сесијама, Gesture Recognizer обрађује до 11 истовремених додира на iPad-у и 5 на iPhone-у. У IT Sectr користимо UIGestureRecognizer као стандардни начин обраде корисничког уноса у свим UIKit пројектима — ово је елиминисало грешке везане за ручно праћење touchesBegan.

Стања UIGestureRecognizer

Сваки UIGestureRecognizer пролази кроз 7 могућих стања, дефинисаних у enum-у UIGestureRecognizer.State. Ова стања одражавају животни циклус препознавања: од одређивања додира до завршетка или отказивања геста. Разумевање стања је кључно за имплементацију прилагођених препознавача и отклањање сукоба.

Стање Значење Када настаје
.possible Почетно стање, гест још није препознат Одмах након додавања на приказ
.began Гест је препознат и почео је да се извршава При првом покрету прста за pan/longPress
.changed Параметри геста су се променили (координате, угао) При сваком покрету прста
.ended Корисник је подигао прст, гест је завршен При touchesEnded
.cancelled Гест је прекинут од стране система (долазни позив, промена оријентације) При touchesCancelled
.failed Гест није препознат према условима При touchesCancelled без препознавања
.recognized Синоним за .ended; гест је успешно препознат Исто као .ended

Дискретни гестови (tap, swipe) прелазе из .possible директно у .ended или .failed. Континуирани гестови (pan, pinch, rotation, longPress) пролазе .possible → .began → .changed (више пута) → .ended. У action методи проверавајте gestureRecognizer.state — то омогућава разликовање почетка, промене и краја геста.

Врсте гестова у iOS

UIKit пружа 7 уграђених подкласа UIGestureRecognizer, које покривају већину сценарија интеракције. Свака подкласа има специфична подешавања: numberOfTapsRequired за тап, direction за превлачење, minimumPressDuration за дуго притискање.

  • UITapGestureRecognizer — препознаје појединачне и вишеструке тапове. Подешава се број додира (numberOfTapsRequired) и прстију (numberOfTouchesRequired). Користи се за дугмад, линкове, избор елемената.
  • UISwipeGestureRecognizer — препознаје превлачење у једном од четири правца (right, left, up, down). Својство direction поставља правац; numberOfTouchesRequired — број прстију.
  • UIPanGestureRecognizer — континуирани гест за превлачење. Метод translation(in:) враћа померај од почетне тачке. Користи се за drag-and-drop, каруселе, pull-to-refresh.
  • UIPinchGestureRecognizer — скалирање са два прста. Својство scale одражава тренутни фактор размере. Детаљно обрађен у чланку Pinch-to-Zoom.
  • UIRotationGestureRecognizer — окретање са два прста. Својство rotation чува угао у радијанима. Користи се за окретање слика, мапа, платана.
  • UILongPressGestureRecognizer — дуго притискање. Параметри minimumPressDuration (секунде), allowableMovement (пиксели). Користи се за контекстне меније, превлачење елемената.
  • UIScreenEdgePanGestureRecognizer — панорамирање са ивице екрана. Својство edges одређује која ивица се прати. Користи се за навигационе гестове, завесе обавештења.

За прилагођене гестове (на пример, цртање цик-цак) креира се подкласа UIGestureRecognizer са преписивањем метода touchesBegan, touchesMoved, touchesEnded и ажурирањем стања. Apple препоручује коришћење уграђених класа где год је могуће — one су оптимизоване и правилно интерагују једна са другом.

Решавање сукоба између гестова

Када се на истом UIView користи више UIGestureRecognizer (на пример, tap и double-tap), настаје сукоб препознавања: при двоструком тапу прво се активира појединачни тап. За решење Apple нуди метод require(toFail:), који одлаже препознавање једног геста док се други не заврши неуспехом.

Механизам ради овако: позивањем tapRecognizer.require(toFail: doubleTapRecognizer), наводите да ће tapRecogniser прећи у стање .recognized тек након што се doubleTapRecogniser заврши у .failed. Ово додаје кашњење од ~0.3 секунде пре извршења појединачног тапа — корисник притиска двапут, а први тап се игнорише. Алтернативни метод — делегат UIGestureRecognizerDelegate са методом gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), који дозвољава истовремено препознавање (на пример, pan + pinch за мапу).

Према WWDC 2020, око 15% грешака у UIKit апликацијама је повезано са неправилним подешавањем сукоба гестова. У IT Sectr смо стандардизовали приступ: за сваки екран се креира шема гестова са приоритетима require(toFail:) — ово је потпуно елиминисало грешке са двоструким активирањем тапова.

Примери кода у Swift

Пример 1: UITapGestureRecognizer — тап на слику

Додаје руковалац појединачним тапом на UIImageView. При тапу слика мења провидност — најједноставнији пример који показује повезивање геста са приказом.

swift
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
        }
    }
}

Кључни моменат: isUserInteractionEnabled на UIImageView подразумевано је false — без ове заставице Gesture Recognizer неће примати додире. За UIView и UIButton заставица је подразумевано укључена. Action метод прима параметар UITapGestureRecognizer преко којег се може добити location(in:) за одређивање координата тапа.

Пример 2: UISwipeGestureRecognizer — превлачење за навигацију

Имплементира превлачење улево за повратак на претходни екран. Демонстрира подешавање правца и повезивање геста са кореним приказом контролера.

swift
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 — дискретни гест: прелази у .recognised одмах након препознавања, без посредног .changed. Стога у акцији није потребно проверавати стање — гест је или препознат (акција се позива) или није. Својство direction прима једну од четири вредности: .left, .right, .up, .down. За подршку више праваца креирајте засебне препознаваче за сваки.

Пример 3: Комбинација гестова са require(toFail:)

Показује како подесити појединачни и двоструки тап на истом приказу без сукоба. Препознавач двоструког тапа има приоритет — појединачни тап се активира само ако двоструки није препознат.

swift
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")
    }
}

Без require(toFail:) при двоструком тапу прво ће се позвати handleSingleTap, затим handleDoubleTap — то квари UX. Са require(toFail:) појединачни тап чека ~0.3 секунде да би се уверио да други тап неће уследити. У IT Sectr овај образац се користи у уређивачима слика и галеријама, где двоструки тап увећава, а појединачни — бира елемент.

Често постављана питања

Може ли се користити више Gesture Recognizer на истом приказу?

Да, UIView подржава више UIGestureRecognizer истовремено. За решавање сукоба користите метод require(toFail:), који поставља редослед препознавања. За паралелни рад гестова (на пример, pan + pinch на мапи) имплементирајте делегата gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), који враћа true.

По чему се UIGestureRecognizer разликује од touchesBegan?

UIGestureRecognizer — апстракција високог нивоа која аутоматски препознаје обрасце додира и управља стањима. touchesBegan — метод ниског нивоа UIResponder који захтева ручно праћење координата, тајминга и отказивање додира. Gesture Recognizer је једноставнији, поузданији и пожељнији за стандардне гестове; touchesBegan је оправдан само за прилагођену графику.

Да ли Gesture Recognizer ради у SwiftUI?

У изворном SwiftUI користе се модификатори: onTapGesture, onLongPressGesture, DragGesture, MagnificationGesture, RotationGesture. То су декларативни аналоги UIGestureRecognizer-а, интегрисани у SwiftUI хијерархију. По потреби можете умотати UIKit препознавач кроз UIViewRepresentable, али Apple препоручује коришћење изворних SwiftUI гестова.

Резиме

  • UIGestureRecognizer — UIKit апстракција за декомпозицију логике препознавања гестова у засебне објекте са аутоматским управљањем стањима.
  • 7 уграђених подкласа покрива 95% типичних гестова: тап, превлачење, панорамирање, штипање, окретање, дуго притискање и превлачење са ивице.
  • Сваки препознавач пролази кроз 7 стања — од .possible до .ended/.failed, што омогућава прецизно праћење дискретних и континуираних гестова.
  • Метод require(toFail:) решава сукобе између гестова на истом приказу, постављајући приоритет препознавања.
  • У SwiftUI се користе декларативни модификатори гестова, али UIKit препознавачи су доступни кроз UIViewRepresentable.
  • Gesture Recognizer је обавезан за UIKit пројекте; touchesBegan је оправдан само за прилагођено цртање и графику ниског нивоа.
  • Користите require(toFail:) за парове tap/double-tap и gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) за паралелне гестове.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође