Sobes.tech
Middle+

Czym jest PreferenceKey w kontekście SwiftUI?

sobes.tech AI

Odpowiedź od AI

PreferenceKey to protokół w SwiftUI, który umożliwia przekazywanie wartości "z dołu do góry" w drzewie widoków. Służy do zbierania informacji od widoków potomnych i dostarczania ich widokom nadrzędnym, które mogą używać tych informacji do zmiany swojego zachowania lub wyglądu.

Kluczowe cechy PreferenceKey:

  • Protokół: Należy zaimplementować protokół PreferenceKey, definiując typ wartości i metodę łączenia wartości.
  • associatedtype Value: Określa typ danych, które będą przekazywane.
  • static func reduce(value: inout Value, nextValue: () -> Value): Ta metoda jest wywoływana przez SwiftUI podczas zbierania wartości od wielu widoków potomnych. Musisz zdefiniować, jak połączyć obecną wartość (value) z nową (nextValue()).
  • Przekazywanie wartości: Widoki potomne używają modyfikatora .preference(key:value:) do ustawiania wartości dla konkretnego PreferenceKey.
  • Odczyt wartości: Widoki nadrzędne używają modyfikatora .onPreferenceChange(_:perform:) do otrzymywania powiadomień o zmianie wartości dla konkretnego PreferenceKey.

Przykład:

Tworzenie PreferenceKey do określenia wysokości widoku potomnego:

struct ChildHeightPreferenceKey: PreferenceKey {
    // Typ wartości - opcjonalny Double, ponieważ widok potomny może jeszcze nie mieć rozmiarów
    typealias Value = Double?

    // Wartość domyślna
    static var defaultValue: Double? = nil

    // Łączenie wartości (w tym przypadku, bierzemy ostatnią niepustą wartość)
    static func reduce(value: inout Double?, nextValue: () -> Double?) {
        value = nextValue() ?? value
    }
}

Użycie w widoku:

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

    var body: some View {
        VStack {
            Text("Wysokość widoku potomnego: \(childHeight != nil ? "\(childHeight!)" : "-")")
            ChildView()
                // Odczytanie wartości 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) // Przykład wysokości
                // Ustawienie wartości PreferenceKey
                .preference(key: ChildHeightPreferenceKey.self, value: geometry.size.height)
        }
        .frame(height: 100) // Stała ramka dla GeometryReader
    }
}