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

Ответ

В 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".

Ответ 18+ 🔞

А, слушай, про эти ваши жесты в SwiftUI! Ну, это ж классика, блядь, вечная путаница у всех новичков. Сейчас разжуем, как есть.

Представь себе, сука, слоёный пирог из представлений. И на каждый слой можно намазать жест, как варенье. Так вот, обычный модификатор .gesture — это такой жадный, ёпта, мудак. Он как только срабатывает, орет на всю кухню: «ВСЁ, ЭТО МОЁ, НАХУЙ! ОСТАЛЬНЫМ ОТСОСАТЬ!». И события жеста дальше не идут, застревают в нём, как пробка в бутылке.

А .simultaneousGesture — это более адекватный товарищ. Он такой: «О, я тоже отработал? Отлично. А ты, родитель, тоже хочешь? Ну давай, обрабатывай, чё уж там». И событие спокойно всплывает наверх, как говно в унитазе.

Главный закон, блядь, который надо выжечь на жопе: ВСЁ ИДЁТ СНИЗУ ВВЕРХ. От мелкого, дочернего, косячного — к большому, родительскому, ответственному. Обычный .gesture этот поток пиздит и останавливает. А simultaneous — пропускает.

Смотри, как это выглядит в коде, когда всё на одном элементе:

// Вот этот круг — упырь-одиночка. Сработает ТОЛЬКО долгое нажатие. Про тап все забудут, как про вчерашний день.
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") }) // И это тоже! Ура, блядь!

А теперь сценарий посложнее, с иерархией. Отец и сын, блядь:

// Большой папа-прямоугольник с тапом
Rectangle()
    .gesture(TapGesture().onEnded { _ in print("Parent Tapped") }) {
        // А внутри сыночек-кружок, тоже с жестом
        Circle()
            .gesture(TapGesture().onEnded { _ in print("Child Tapped") }) // Сработает ТОЛЬКО ЭТОТ, эгоист ёбаный. Папа в ауте.
    }
// НО! Если у круга заменить .gesture на .simultaneousGesture,
// то будет праздник: сначала "Child Tapped", а потом и "Parent Tapped"!
// Воссоединение семьи, ебать его в сраку!

Вот и вся магия, ёпта. Не хочешь конфликтов — юзай simultaneous. Хочешь жёсткого контроля, чтобы дитё не лезло со своим мнением — exclusive (то есть обычный .gesture). Выбирай, как тебе удобнее, главное — не путай, а то начнётся волнение ебать, где чей жест сработал.