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

В чем разница между Gesture и simultaneousGesture?

1.0 Junior🔥 82 комментариев
#SwiftUI

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

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

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

Разница между Gesture и simultaneousGesture

В UIKit и SwiftUI обработка жестов — ключевая часть создания интерактивных интерфейсов. Разница между gesture и simultaneousGesture фундаментальна и связана с тем, как система обрабатывает конфликты жестов при их наложении на иерархию представлений.

Основная философия обработки жестов

Система жестов работает по принципу "победитель получает всё" (winner-takes-all). Когда несколько жестов могут распознать одно касание, только один из них становится активным жестом (exclusive gesture). Это предотвращает хаотичное поведение, когда, например, и прокрутка, и увеличение срабатывают одновременно от одного касания.


Gesture (Обычный, эксклюзивный жест)

Модификатор .gesture в SwiftUI (или добавление UIGestureRecognizer в UIKit) устанавливает жест, который конкурирует с другими жестами в своей цепочке предков и потомков. Если этот жест начинает распознаваться, он "заблокирует" распознавание многих других жестов в этой области.

Пример в SwiftUI:

VStack {
    Text("Прокручиваемая область")
        .frame(height: 200)
        .background(Color.blue)
        .gesture(
            DragGesture()
                .onChanged { _ in print("Перетаскивание текста") }
        )
    
    Circle()
        .fill(Color.red)
        .frame(width: 100, height: 100)
        .gesture(
            TapGesture()
                .onEnded { _ in print("Тап по кругу") }
        )
}

В этом примере, если жест начинается на тексте, тап по кругу не сработает, пока жест перетаскивания не завершится или не будет отменен.


SimultaneousGesture (Одновременный жест)

Модификатор .simultaneousGesture позволяет жесту распознаваться одновременно с жестами, установленными на дочерних представлениях. Это ключевое отличие — жесты больше не конкурируют, а сосуществуют.

Типичный use case: Контейнер (например, ScrollView или List) имеет собственные жесты для прокрутки, но вы хотите добавить дополнительный жест (например, долгое нажатие для контекстного меню) на элементы внутри контейнера, не блокируя прокрутку.

Пример в SwiftUI:

ScrollView {
    ForEach(0..<20) { index in
        Text("Элемент \(index)")
            .padding()
            .frame(maxWidth: .infinity)
            .background(Color.gray.opacity(0.2))
            .simultaneousGesture(
                LongPressGesture()
                    .onEnded { _ in
                        print("Долгое нажатие на элемент \(index)")
                    }
            )
    }
}

Здесь ScrollView использует DragGesture для прокрутки. Благодаря simultaneousGesture на элементах списка, вы можете:

  1. Прокручивать список обычным перетаскиванием
  2. Вызывать контекстное действие долгим нажатием на конкретный элемент, не блокируя основную прокрутку

Технические детали и приоритеты

В SwiftUI существует иерархия разрешения конфликтов:

  1. Высший приоритет — жесты с явно заданным высоким .highPriorityGesture
  2. Одновременные жесты.simultaneousGesture может сосуществовать с другими
  3. Обычные жесты.gesture блокирует распознавание жестов потомков

В UIKit аналоги достигаются через:

  • Делегаты жестов (UIGestureRecognizerDelegate) с методом gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
  • Настройку зависимостей между распознавателями жестов
// UIKit пример: разрешение одновременного распознавания
class ViewController: UIViewController, UIGestureRecognizerDelegate {
    func setupGestures() {
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
        let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
        
        panGesture.delegate = self
        longPressGesture.delegate = self
    }
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, 
                          shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // Разрешаем одновременное распознавание жестов
        return true
    }
}

Когда что использовать?

  • Используйте .gesture, когда нужен эксклюзивный жест, который должен блокировать другие взаимодействия (например, перетаскивание элемента в режиме редактирования).
  • Используйте .simultaneousGesture, когда нужно добавить поведение к существующим жестам без их блокировки (например, контекстное меню в прокручиваемом списке).

Важное замечание: simultaneousGesture не означает, что все жесты будут работать одновременно всегда. Жесты должны быть совместимы по типу — например, TapGesture и LongPressGesture технически не могут распознаваться одновременно от одного касания, так как имеют разные временные критерии.

В чем разница между Gesture и simultaneousGesture? | PrepBro