Что такое GeometryReader в SwiftUI и для чего он используется?

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

Ответ

GeometryReader — это контейнерный view в SwiftUI, который предоставляет своим дочерним view информацию о размере и координатах пространства, выделенного ему родительской view-иерархией.

Основная цель: Создание адаптивных и сложных layout'ов, которые зависят от доступного пространства, а не от фиксированных размеров.

Как работает: GeometryReader принимает замыкание с параметром типа GeometryProxy. Этот объект содержит необходимые геометрические данные.

Пример: Адаптивный квадрат

GeometryReader { geometry in
    Rectangle()
        .fill(Color.blue)
        .frame(
            width: min(geometry.size.width, geometry.size.height), // Квадрат по меньшей стороне
            height: min(geometry.size.width, geometry.size.height)
        )
        .position(x: geometry.size.width / 2, y: geometry.size.height / 2) // Центрирование
}
.frame(width: 300, height: 150) // GeometryReader займет эти 300x150 точек

Данные в GeometryProxy:

  • size: CGSize — текущий размер GeometryReader.
  • safeAreaInsets: EdgeInsets — отступы безопасной зоны устройства.
  • frame(in: CoordinateSpace) -> CGRect — возвращает frame контейнера в заданной системе координат.
    • .global — относительно всего экрана.
    • .local — относительно собственных границ (по умолчанию).
    • .named(...) — относительно пользовательской системы координат.

Важные особенности и предостережения:

  1. «Жадное» поведение: GeometryReader по умолчанию стремится занять все предложенное ему пространство. Чтобы ограничить его, явно задавайте .frame().
    GeometryReader { proxy in ... }
        .frame(height: 100) // Ограничиваем высоту
  2. Использование для чтения, а не изменения layout'а: Не используйте GeometryReader для передачи размеров вверх по иерархии view (например, чтобы изменить размер родителя). Это противоречит однонаправленному потоку данных SwiftUI. Вместо этого используйте .readSize модификатор или предпочтения (PreferenceKey).

Типичные сценарии использования:

  • Создание кастомных прогресс-баров, слайдеров.
  • Адаптивные сетки или раскладки с пропорциональными размерами.
  • Сложные анимации, зависящие от позиции элементов.
  • Учет safe area при ручном позиционировании.