January 13, 2024

49. Получаем размер вьюшки в SwiftUI

Иногда бывает нужно получить размер вьюшки, чтобы сверстать что-то особым образом. Например, нужно расположить один UI-элемент на определенном расстоянии от другого, но они оба находятся в разных контейнерах, т.е. обычным VStack/HStack и спейсингом не обойтись.

Есть достаточно простое решение для такой ситуации: GeometryReader + PreferenceKey, и в этой статье покажу как с этим работать.

Будем использовать PreferenceKey, как это часто бывает, для передачи информации о вьюхе наверх по иерархии вьюшек:

struct SizePreferenceKey: PreferenceKey {
 static var defaultValue: CGSize = .zero
 static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}

Делаем модификатор для получения размера:

extension View {
  /// Возвращает размер вьюхи в замыкании
  func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
    background(
      GeometryReader { geometry in // <- незаменимый и неповторимый
        Color.clear
          .preference(key: SizePreferenceKey.self, value: geometry.size)
      }
    )
    .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
  }
}
Демо работы модификатора для получения размера вьюшки

Код для этой статьи можно посмотреть тут, а другие статьи - тут.