I have been engaged on a SwiftUI venture the place I wanted to dynamically monitor the dimensions of particular views and the complete machine display screen. One problem was making certain that the dimensions updates correctly when the machine orientation modifications with out breaking the format.
I created a reusable resolution utilizing GeometryReader and PreferenceKey. It captures each the subview measurement and the display screen measurement dynamically and could be utilized flexibly throughout totally different views. Beneath is the implementation.
I might love to listen to your ideas on this method or recommendations for additional optimization!
import Basis
import SwiftUI
// PreferenceKey to retailer and replace the dimensions worth
struct DimensionKey: PreferenceKey {
static let defaultValue: CGSize = .zero
static func scale back(worth: inout CGSize, nextValue: () -> CGSize) {
worth = nextValue()
}
}
// Extension on View for reusable measurement monitoring modifiers
extension View {
// Modifier for monitoring the dimensions of a selected content material view
func contentSizePreferenceModifier(measurement: @escaping (CGSize) -> Void) -> some View {
self
.background(
GeometryReader { proxy in
Colour.clear
.choice(key: DimensionKey.self, worth: proxy.measurement)
.onPreferenceChange(DimensionKey.self, carry out: measurement)
}
)
}
// Modifier for monitoring the display screen measurement
func screenSizePreferenceModifier(measurement: @escaping (CGSize) -> Void) -> some View {
ZStack {
GeometryReader { proxy in
Colour.yellow.ignoresSafeArea()
.choice(key: DimensionKey.self, worth: proxy.measurement)
.onPreferenceChange(DimensionKey.self, carry out: measurement)
}
self
}
}
}
// The primary view to show the utilization of measurement monitoring
struct DataView: View {
@State non-public var deviceSize: CGSize = .zero
@State non-public var contentSize: CGSize = .zero
var physique: some View {
VStack {
Textual content("Account Info")
.font(.largeTitle)
Group {
Textual content("Display screen Width: (deviceSize.width, specifier: "%.2f")")
Textual content("Display screen Peak: (deviceSize.peak, specifier: "%.2f")")
.padding(.backside)
}
.font(.title)
VStack {
Textual content("Content material Width: (contentSize.width, specifier: "%.2f")")
Textual content("Content material Peak: (contentSize.peak, specifier: "%.2f")")
}
.font(.title)
.foregroundStyle(.white)
.background(Colour.purple)
.contentSizePreferenceModifier { measurement in
contentSize = measurement
}
}
.screenSizePreferenceModifier { measurement in
deviceSize = measurement
}
}
}
// Preview for SwiftUI
#Preview {
DataView()
}
The rationale I used ZStack is that it does not have an effect on the format of the view the modifier is utilized to. It’s because GeometryReader sometimes takes up all accessible house, which may disrupt the unique format. By utilizing ZStack, the modifier solely tracks the dimensions with out interfering with the precise content material view.
Any recommendations for enhancements?