import SwiftUI
// MARK: - Size Preference
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct MeasurableView<Content: View>: View {
let content: Content
@Binding var size: CGSize
init(size: Binding<CGSize>, @ViewBuilder content: () -> Content) {
self._size = size
self.content = content()
}
var body: some View {
content
.background(
GeometryReader { geometry in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometry.size)
}
)
.onPreferenceChange(SizePreferenceKey.self) { newSize in
size = newSize
}
}
}
// MARK: - Scroll Offset Preference
struct ScrollOffsetPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
struct TrackableScrollView<Content: View>: View {
let content: Content
@Binding var scrollOffset: CGFloat
init(scrollOffset: Binding<CGFloat>, @ViewBuilder content: () -> Content) {
self._scrollOffset = scrollOffset
self.content = content()
}
var body: some View {
ScrollView {
GeometryReader { geometry in
Color.clear
.preference(
key: ScrollOffsetPreferenceKey.self,
value: geometry.frame(in: .named("scrollView")).minY
)
}
.frame(height: 0)
content
}
.coordinateSpace(name: "scrollView")
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { offset in
scrollOffset = offset
}
}
}
// MARK: - Multiple Values Collection
struct ViewHeightKey: PreferenceKey {
static var defaultValue: [Int: CGFloat] = [:]
static func reduce(value: inout [Int: CGFloat], nextValue: () -> [Int: CGFloat]) {
value.merge(nextValue()) { $1 }
}
}
struct AdaptiveStack<Content: View>: View {
let content: Content
@State private var heights: [Int: CGFloat] = [:]
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
content
.onPreferenceChange(ViewHeightKey.self) { heights in
self.heights = heights
}
}
}
// Usage example
struct DynamicHeightExample: View {
@State private var headerSize: CGSize = .zero
@State private var scrollOffset: CGFloat = 0
var body: some View {
VStack {
MeasurableView(size: $headerSize) {
Text("Dynamic Header")
.font(.largeTitle)
.padding()
.background(Color.blue)
}
Text("Header size: \(headerSize.width) x \(headerSize.height)")
TrackableScrollView(scrollOffset: $scrollOffset) {
ForEach(0..<50) { index in
Text("Row \(index)")
.padding()
}
}
Text("Scroll offset: \(scrollOffset)")
}
}
}
PreferenceKey enables child views to pass data up to ancestors, complementing the typical parent-to-child flow. I define a custom preference key by conforming to PreferenceKey protocol with a defaultValue and reduce method that combines multiple values. Child views set preferences with .preference(key:value:) modifier. Parent views read them with .onPreferenceChange(). Common use cases include measuring child sizes, collecting scroll positions, and building custom layouts. For anchors, Anchor preferences pass geometry information. This pattern enables complex layouts like badges on tab bars or dynamic height containers. PreferenceKeys make SwiftUI layouts more flexible without breaking the declarative paradigm.
Related snips
import Combine
import Foundation
class SearchViewModel: ObservableObject {
@Published var searchQuery = ""
@Published var results: [SearchResult] = []
Combine operators for data transformation
import SwiftUI
struct ContentView: View {
@State private var username = ""
@State private var isLoggedIn = false
@StateObject private var viewModel = LoginViewModel()
SwiftUI declarative UI with state management
import SwiftUI
struct CardModifier: ViewModifier {
var backgroundColor: Color = .white
var cornerRadius: CGFloat = 12
var shadowRadius: CGFloat = 5
Custom SwiftUI view modifiers for reusability
import Foundation
import UIKit
class ImageProcessor {
// Background processing with main thread updates
func processImage(_ image: UIImage, completion: @escaping (UIImage?) -> Void) {
Grand Central Dispatch for concurrency
import SwiftUI
enum Route: Hashable {
case postDetail(id: Int)
case userProfile(id: Int)
case settings
Navigation patterns with NavigationStack
import UIKit
import WebKit
class WebViewController: UIViewController {
private var webView: WKWebView!
private var progressView: UIProgressView!
WKWebView for web content display
Share this code
Here's the card — post it anywhere.