Ответ
PreferenceKey — это протокол в SwiftUI, который позволяет дочерним представлениям передавать данные вверх по иерархии к общему предку, не требуя прямых связей. Это ключевой механизм для координации состояния между представлениями.
Основные компоненты:
defaultValue: Статическое значение по умолчанию.reduce(value:nextValue:): Функция, которая объединяет значения от всех дочерних представлений в одно.
Зачем это нужно? Для реализации сложной компоновки, когда родительскому виду нужно знать размеры или состояние своих детей (например, для выравнивания, построения тулбаров или кастомной навигации).
Пример: Передача размера дочернего вида
// 1. Определяем ключ предпочтения
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue() // В данном примере берем последнее значение
}
}
// 2. Дочернее представление отправляет свой размер
struct ChildView: View {
var body: some View {
Color.blue
.frame(width: 200, height: 150)
.background(GeometryReader { geometry in
Color.clear
.preference(key: SizePreferenceKey.self,
value: geometry.size)
})
}
}
// 3. Родительское представление читает и использует размер
struct ParentView: View {
@State private var childSize: CGSize = .zero
var body: some View {
VStack {
ChildView()
Text("Размер ребенка: (Int(childSize.width))x(Int(childSize.height))")
}
.onPreferenceChange(SizePreferenceKey.self) { newSize in
childSize = newSize
}
}
}
Ключевые моменты:
- Для чтения геометрии часто используется
GeometryReader. onPreferenceChangeсрабатывает каждый раз, когда значение ключа меняется в любом дочернем представлении.- Метод
reduceопределяет, как агрегировать множественные значения (например, можно суммировать их или находить максимум).