← Назад к вопросам

Как объявить обработчика жестов?

1.0 Junior🔥 171 комментариев
#UIKit и верстка

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Объявление обработчиков жестов в iOS разработке

В iOS существует несколько основных способов объявления обработчиков жестов, каждый из которых подходит для разных сценариев. Рассмотрим основные подходы.

1. Target-Action с использованием addGestureRecognizer

Наиболее распространенный способ — программное создание UIGestureRecognizer и добавление его к представлению с указанием метода-обработчика.

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Создаем жестовый распознаватель
        let tapGesture = UITapGestureRecognizer(
            target: self, 
            action: #selector(handleTap(_:))
        )
        
        // Настраиваем параметры (опционально)
        tapGesture.numberOfTapsRequired = 1
        tapGesture.numberOfTouchesRequired = 1
        
        // Добавляем распознаватель к представлению
        view.addGestureRecognizer(tapGesture)
        
        // Пример с несколькими жестами
        let pinchGesture = UIPinchGestureRecognizer(
            target: self, 
            action: #selector(handlePinch(_:))
        )
        view.addGestureRecognizer(pinchGesture)
    }
    
    @objc private func handleTap(_ gesture: UITapGestureRecognizer) {
        let location = gesture.location(in: view)
        print("Тап распознан в точке: \(location)")
        
        // Дополнительная логика обработки
        if gesture.state == .ended {
            // Выполняем действия при завершении жеста
        }
    }
    
    @objc private func handlePinch(_ gesture: UIPinchGestureRecognizer) {
        let scale = gesture.scale
        print("Масштабирование: \(scale)")
    }
}

2. Использование UIGestureRecognizerDelegate

Для более сложной логики взаимодействия с жестами используется протокол UIGestureRecognizerDelegate.

class GestureViewController: UIViewController, UIGestureRecognizerDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let panGesture = UIPanGestureRecognizer(
            target: self, 
            action: #selector(handlePan(_:))
        )
        panGesture.delegate = self
        view.addGestureRecognizer(panGesture)
        
        let swipeGesture = UISwipeGestureRecognizer(
            target: self, 
            action: #selector(handleSwipe(_:))
        )
        swipeGesture.direction = [.left, .right]
        swipeGesture.delegate = self
        view.addGestureRecognizer(swipeGesture)
    }
    
    // Делегатный метод для одновременной обработки жестов
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, 
                          shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // Разрешаем одновременную работу pan и swipe жестов
        return true
    }
    
    // Делегатный метод для требования других жестов к провалу
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                          shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // Настраиваем приоритеты жестов
        return false
    }
}

3. IBOutlets и Interface Builder

Визуальное создание жестов через Storyboard/XIB с подключением через @IBAction.

class StoryboardViewController: UIViewController {
    
    // 1. Перетащите Gesture Recognizer из библиотеки объектов на представление в Storyboard
    // 2. Создайте IBAction связь
    
    @IBAction func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
        switch gesture.state {
        case .began:
            print("Долгое нажатие начато")
        case .changed:
            let location = gesture.location(in: view)
            print("Изменение позиции: \(location)")
        case .ended:
            print("Долгое нажатие завершено")
        default:
            break
        }
    }
    
    // Можно также создать IBOutlet для жеста
    @IBOutlet weak var customGesture: UIRotationGestureRecognizer!
    
    @IBAction func handleRotation(_ gesture: UIRotationGestureRecognizer) {
        let rotation = gesture.rotation
        print("Вращение: \(rotation) радиан")
    }
}

4. Современный подход с UIGestureRecognizer closures (iOS 14+)

Начиная с iOS 14, появилась удобная возможность использовать замыкания.

class ModernViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let doubleTapGesture = UITapGestureRecognizer()
        doubleTapGesture.numberOfTapsRequired = 2
        
        // Использование замыкания для обработки
        doubleTapGesture.addAction { [weak self] _ in
            guard let self = self else { return }
            self.handleDoubleTap()
        }
        
        view.addGestureRecognizer(doubleTapGesture)
        
        // Альтернативный синтаксис с UIAction
        let swipeAction = UIAction { [weak self] _ in
            self?.handleSwipeAction()
        }
        
        let swipeGesture = UISwipeGestureRecognizer(
            direction: .up,
            primaryAction: swipeAction
        )
        view.addGestureRecognizer(swipeGesture)
    }
    
    private func handleDoubleTap() {
        print("Двойной тап обработан через замыкание")
    }
    
    private func handleSwipeAction() {
        print("Свайп обработан через UIAction")
    }
}

5. Кастомные жесты через наследование

Создание собственных обработчиков жестов путем наследования от UIGestureRecognizer.

class CircleGestureRecognizer: UIGestureRecognizer {
    private var points: [CGPoint] = []
    private let tolerance: CGFloat = 20.0
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        points.removeAll()
        
        if let touch = touches.first {
            points.append(touch.location(in: view))
        }
        
        state = .began
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        
        if let touch = touches.first {
            points.append(touch.location(in: view))
            
            if isCircle() {
                state = .ended
            } else {
                state = .changed
            }
        }
    }
    
    private func isCircle() -> Bool {
        // Логика определения кругового жеста
        return points.count > 10 // Упрощенная проверка
    }
}

Ключевые рекомендации:

  • Используйте .state жеста для обработки разных фаз (.began, .changed, .ended, .cancelled)
  • Учитывайте приоритеты жестов через методы делегата при наличии нескольких жестов
  • Не забывайте про weak self в замыканиях для избежания циклов удержания
  • Тестируйте на реальных устройствах, так как симулятор может не полностью эмулировать мультитач
  • Оптимизируйте производительность при обработке жестов в реальном времени (например, при рисовании)

Выбор конкретного способа зависит от требований проекта: для простых случаев достаточно target-action, для сложной логики взаимодействия — делегаты, а для современного кода — замыкания.