Назад к вопросам
Middle+
345
questionbank

Что такое PreferenceKey в контексте SwiftUI?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

PreferenceKey — это протокол в SwiftUI, который позволяет передавать значения "снизу вверх" по дереву представлений. Он используется для сбора информации от дочерних представлений и доставки ее родительским, которые могут использовать эту информацию для изменения своего поведения или внешнего вида.

Ключевые особенности PreferenceKey:

  • Протокол: Нужно реализовать протокол PreferenceKey, определяя тип значения и метод для комбинирования значений.
  • associatedtype Value: Определяет тип данных, который будет передаваться.
  • static func reduce(value: inout Value, nextValue: () -> Value): Этот метод вызывается SwiftUI при сборе значений от нескольких дочерних представлений. Вы должны определить, как объединить текущее значение (value) с новым (nextValue()).
  • Передача значений: Дочерние представления используют модификатор .preference(key:value:) для установки значения для конкретного PreferenceKey.
  • Чтение значений: Родительские представления используют модификатор .onPreferenceChange(_:perform:) для получения уведомлений об изменении значения для конкретного PreferenceKey.

Пример:

Создание PreferenceKey для определения высоты дочернего представления:

struct ChildHeightPreferenceKey: PreferenceKey {
    // Тип значения - Optional Double, так как дочернее представление может еще не иметь размеров
    typealias Value = Double?

    // Начальное значение
    static var defaultValue: Double? = nil

    // Объединение значений (в данном случае, берем последнее непустое значение)
    static func reduce(value: inout Double?, nextValue: () -> Double?) {
        value = nextValue() ?? value
    }
}

Использование в представлении:

struct ParentView: View {
    @State private var childHeight: Double? = nil

    var body: some View {
        VStack {
            Text("Высота дочернего представления: \(childHeight != nil ? "\(childHeight!)" : "-")")
            ChildView()
                // Чтение значения PreferenceKey
                .onPreferenceChange(ChildHeightPreferenceKey.self) { newValue in
                    self.childHeight = newValue
                }
        }
    }
}

struct ChildView: View {
    var body: some View {
        GeometryReader { geometry in
            Rectangle()
                .fill(Color.blue)
                .frame(height: 100) // Пример высоты
                // Установка значения PreferenceKey
                .preference(key: ChildHeightPreferenceKey.self, value: geometry.size.height)
        }
        .frame(height: 100) // Фиксированная рамка для GeometryReader
    }
}