Introduction
In SwiftUI, data generally flows downwards, meaning data is passed from parent views to child views. However, there are situations where you may want to pass data in the opposite direction—from a child view to a parent view.
SwiftUI’s PreferenceKey protocol is a powerful solution for these cases. PreferenceKey enables data to travel up the view hierarchy, allowing parent views to access values defined in their child views.
Creating a Custom PreferenceKey
To create a PreferenceKey, start by defining a new struct that conforms to the PreferenceKey protocol. This struct must have a defaultValue and a reduce function to aggregate multiple values.
struct MyPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value += nextValue()
}
}
In this example, MyPreferenceKey has a CGFloat value, with a defaultValue set to 0, and the reduce function aggregates values by adding them up.
Applying the PreferenceKey to a View
After creating a PreferenceKey, apply it to a view using the preference modifier. This allows you to specify a value for the PreferenceKey within the child view.
Text("Hello, SwiftUI!")
.background(GeometryReader { geometry in
Color.clear.preference(key: MyPreferenceKey.self, value: geometry.size.height)
})
In this example, a GeometryReader calculates the height of a Text view, which is then stored as a PreferenceKey value using the preference modifier.
Reading a PreferenceKey Value
To access a PreferenceKey value, use the onPreferenceChange modifier in the parent view. This allows you to respond to changes in the preference value.
VStack {
Text("Hello, SwiftUI!")
.background(GeometryReader { geometry in
Color.clear.preference(key: MyPreferenceKey.self, value: geometry.size.height)
})
}
.onPreferenceChange(MyPreferenceKey.self) { value in
print("Height of Text view: \(value)")
}
In this example, onPreferenceChange monitors changes in MyPreferenceKey and prints the height of the Text view whenever it changes.
Be the first to comment