Using PreferenceKey for Custom Data Passing in SwiftUI

 

SwiftUI provides several mechanisms for passing data between views, such as @State, @Binding, @Environment, and ObservableObject. However, when dealing with data propagation from child views to parent viewsPreferenceKeyoffers a powerful and flexible approach.

This blog explores PreferenceKey, its use cases, and how to implement it to pass custom data efficiently.

What is PreferenceKey?

PreferenceKey allows child views to communicate values to their parent views in SwiftUI’s view hierarchy. Unlike @Binding, which is used for parent-to-child data flow, PreferenceKey facilitates the reverse flow (child-to-parent).

Use Cases of PreferenceKey

  • Passing custom view properties (e.g., geometry size, offset) to parent views.
  • Creating custom layout behaviors.
  • Managing global state for subviews.

Creating a Custom PreferenceKey

Let’s walk through a practical example where a child view updates the parent view with its width dynamically.

Step 1: Define a Custom PreferenceKey

import SwiftUI

struct WidthPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = max(value, nextValue()) // Keeps the maximum width
}
}

Explanation:

  • defaultValue: Provides an initial value.
  • reduce: Defines how values from multiple children combine. Here, we keep the maximum width.

Step 2: Updating the Parent View

Now, we use the WidthPreferenceKey to pass a child view's width to its parent.

struct ChildView: View {
var body: some View {
Text("Hello, SwiftUI!")
.padding()
.background(Color.blue)
.overlay(GeometryReader { geometry in
Color.clear.preference(key: WidthPreferenceKey.self, value: geometry.size.width)
})
}
}

Explanation:

  • GeometryReader is used to fetch the width of Text.
  • .preference(key:value:) updates the parent view with this width.

Step 3: Reading the Preference in the Parent View

The parent view listens for the PreferenceKey value and updates its state accordingly.

struct ParentView: View {
@State private var childWidth: CGFloat = 0

var body: some View {
VStack {
ChildView()
.onPreferenceChange(WidthPreferenceKey.self) { newValue in
childWidth = newValue // Update the state
}

Text("Child View Width: \(childWidth, specifier: "%.2f")")
.padding()
.background(Color.green)
}
}
}

Explanation:

  • @State childWidth stores the value passed from the child.
  • onPreferenceChange listens for updates and modifies the @State variable.

Practical Use Cases

1. Custom Navigation Bar Height

Use PreferenceKey to get the height of a custom navigation bar and adjust the layout dynamically.

2. Synchronizing Scroll Positions

Sync multiple ScrollView components by passing scroll positions using a custom PreferenceKey.

3. Responsive Layouts

Determine child view sizes dynamically to adjust the parent’s layout behavior.

Conclusion

PreferenceKey is a powerful yet underutilized SwiftUI feature that enables efficient child-to-parent communication. It is particularly useful in cases where traditional property wrappers like @Binding or @EnvironmentObject are insufficient.

✅ Key Takeaways:

  • Allows data passing from child to parent.
  • Works well with dynamic layouts and view measurements.
  • Helps in creating custom UI behaviors and interactions.

Comments

Popular posts from this blog

Dependency Injection in iOS with SwiftUI

Using Core ML with SwiftUI: Build an AI-Powered App

CI/CD for iOS Projects with Xcode: A Complete Guide