Как стать автором
Обновить

clipped() не оказывает влияния на проверку касаний

Время на прочтение2 мин
Количество просмотров1K
Автор оригинала: Ole Begemann

Модификатор clipped() в SwiftUI обрезает вью до своих(модификатора) границ, скрывая все, что выходит за пределы этих границ. Но обратите внимание, что обрезание не влияет на проверку касаний (hit testing); обрезанный вью по-прежнему принимает тапы / клики за пределами видимой области.

Протестировано на iOS 16.1 и macOS 13.0.

Пример

У нас есть квадрат 300×300, который затем мы ограничиваем кадром 100×100. Также добавим границу вокруг внешней рамки, чтобы визуализировать вью:

Rectangle()
  .fill(.orange.gradient)
  .frame(width: 300, height: 300)
  // Set view to 100×100 → renders out of bounds
  .frame(width: 100, height: 100)
  .border(.blue)

Вьюшки в SwiftUI по умолчанию не обрезают свой контент, поэтому весь квадрат размером 300×300 остается видимым. Обратите внимание на синюю рамку, обозначающую границы кадра 100×100:

Теперь давайте добавим .clipped(),
чтобы обрезать большой квадрат до кадра 100×100. Я также сделал квадрат
кликабельным и добавил кнопку:

VStack {
  Button("You can't tap me!") {
    buttonTapCount += 1
  }
  .buttonStyle(.borderedProminent)

  Rectangle()
    .fill(.orange.gradient)
    .frame(width: 300, height: 300)
    .frame(width: 100, height: 100)
    .clipped()
    .onTapGesture {
      rectTapCount += 1
    }
}

Когда вы запустите этот код, вы обнаружите, что кнопка не нажимается совсем. Это связано с тем, что (необрезанный) квадрат, несмотря на то, что он виден не полностью, закрывает(затеняет) эту кнопку и «крадет» все нажатия.

Пунктирная линия обозначает область нажатия для оранжевого квадрата. Кнопку нельзя нажать, т.к. она закрыта обрезанным вью относительно к hit testing.
Пунктирная линия обозначает область нажатия для оранжевого квадрата. Кнопку нельзя нажать, т.к. она закрыта обрезанным вью относительно к hit testing.

Решение: .contentShape()

Модификатор contentShape(_:) определяет область проверки
касания для вью. Добавляя .contentShape(Rectangle()) к кадру 100×100, мы ограничиваем проверку касания
этой областью, делая кнопку снова доступной для нажатия:

Rectangle()
    .fill(.orange.gradient)
    .frame(width: 300, height: 300)
    .frame(width: 100, height: 100)
    .contentShape(Rectangle())
    .clipped()

Обратите внимание, что порядок .contentShape(Rectangle()) и .clipped() можно поменять местами. Важно то, что contentShape является (косвенным) родителем модификатора кадра 100×100, который определяет размер области проверки касания.

Видео

Я сделал короткое видео, демонстрирующее эффект:

  • Первоначально нажатия на кнопку или даже на окружающее пустое пространство регистрируются как нажатия на квадрат.

  • Верхний переключатель дает нам увидеть квадрат перед обрезкой. Тем самым показывая нам его область проверки касаний.

  • Второй переключатель добавляет .contentShape(Rectangle()) , ограничивая проверку попаданий видимой(оранжевой) областью. Теперь нажатие кнопки увеличивает счет нажатий на нее.

Полный код доступен на GitHub.

Итог

Модификатор clipped() не влияет на область проверки касания для обрезанного вью. То же самое верно и для clipShape(_:). Часто рекомендуется комбинировать эти модификаторы с .contentShape(Rectangle()), чтобы синхронизировать логику проверки касания с UI.

Оригинал статьи

Теги:
Хабы:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Публикации

Истории

Работа

Swift разработчик
39 вакансий
iOS разработчик
32 вакансии

Ближайшие события

One day offer от ВСК
Дата16 – 17 мая
Время09:00 – 18:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург
Summer Merge
Дата28 – 30 июня
Время11:00
Место
Ульяновская область