В чем разница между модификаторами .gesture и .simultaneousGesture в SwiftUI?

«В чем разница между модификаторами .gesture и .simultaneousGesture в SwiftUI?» — вопрос из категории SwiftUI, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В SwiftUI модификаторы .gesture и .simultaneousGesture управляют тем, как представление обрабатывает жесты, особенно при их наложении.

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

Ключевое правило: Жесты обрабатываются от дочернего представления к родительскому. .gesture обычно "поглощает" событие, предотвращая его всплытие. .simultaneousGesture позволяет событию всплывать дальше.

Пример: Конфликт жестов на одном элементе

// Сработает ТОЛЬКО LongPressGesture, TapGesture будет проигнорирован.
Circle()
    .gesture(LongPressGesture().onEnded { _ in print("Long Press") })
    .gesture(TapGesture().onEnded { _ in print("Tap") }) // Не сработает

// Сработают ОБА жеста одновременно.
Circle()
    .simultaneousGesture(LongPressGesture().onEnded { _ in print("Long Press") })
    .simultaneousGesture(TapGesture().onEnded { _ in print("Tap") }) // Сработает

Пример: Иерархия представлений

// Родительский контейнер с TapGesture
Rectangle()
    .gesture(TapGesture().onEnded { _ in print("Parent Tapped") }) {
        // Дочерний круг с exclusive жестом
        Circle()
            .gesture(TapGesture().onEnded { _ in print("Child Tapped") }) // Сработает только этот
    }
// Если заменить .gesture у Circle на .simultaneousGesture,
// сработают оба: "Child Tapped", а затем "Parent Tapped".