I’m making an attempt to calculate the display screen measurement and content material measurement of a view in my SwiftUI app. Nevertheless, I’ve encountered the next points:
1. Mismatch Between geometry.measurement and UIScreen.primary.bounds:
-
When utilizing geometry.measurement in a GeometryReader, the size don’t
match UIScreen.primary.bounds as a result of the previous excludes protected space
insets, whereas the latter consists of them. -
To resolve this, I added the protected space insets to geometry.measurement utilizing
the getTotalSize operate in my code.
2. Points in iOS 16.4 Simulator When Orientation Modifications:
-
My code works effective in iOS 15, iOS 17, and iOS 16 units, however not in
the iOS 16.4 simulator. -
To deal with this, I attempted updating the dimensions utilizing .onChange(of:
geometry.safeAreaInsets) as an alternative of .onChange(of: geometry.measurement).
This workaround appears to resolve the difficulty for all situations.
3. onGeometryChange modifier Not Discovered:
- I tried to make use of onGeometryChange, which is meant to deal with
geometry modifications extra elegantly. Nevertheless, I get the next error:
Worth of kind ‘ContentSizeViewModifier.Content material’ (aka ‘_ViewModifier_Content’) has no member
‘onGeometryChange’.
My Code
import SwiftUI
struct ContentView: View {
@State non-public var contentSize: CGSize = .zero
@State non-public var screenSize: CGSize = .zero
var physique: some View {
HStack {
VStack(spacing: 10) {
Textual content("Display screen width: (screenSize.width) (UIScreen.primary.bounds.width)")
Textual content("Display screen peak: (screenSize.peak) (UIScreen.primary.bounds.peak)")
HStack {
Spacer()
VStack {
Textual content("Howdy World")
.font(.largeTitle)
Textual content("Welcome to World")
.font(.title)
}
Spacer()
}
.background(Colour.yellow)
.contentSize(measurement: $contentSize)
Textual content("Content material width: (contentSize.width)")
Textual content("Content material peak: (contentSize.peak)")
}
}
.screenSize(measurement: $screenSize)
}
}
struct ScreenSizeViewModifier: ViewModifier {
@Binding var measurement: CGSize
func physique(content material: Content material) -> some View {
ZStack {
Colour.clear
content material
}
.ignoresSafeArea()
.contentSize(measurement: $measurement)
}
}
struct ContentSizeViewModifier: ViewModifier {
@Binding var measurement: CGSize
func getTotalSize(geometry: GeometryProxy) -> CGSize {
let (measurement, safeAreaInsets) = (geometry.measurement, geometry.safeAreaInsets)
var width: CGFloat = measurement.width
var peak: CGFloat = measurement.peak
width += safeAreaInsets.main + safeAreaInsets.trailing
peak += safeAreaInsets.prime + safeAreaInsets.backside
return CGSize(width: width, peak: peak)
}
func physique(content material: Content material) -> some View {
// if #obtainable(iOS 16, *) {
// content material
// .onGeometryChange(for: CGSize.self) { proxy in
// proxy.measurement
// } motion: { newVal in
// measurement = newVal
// }
// } else {
content material
.background(
GeometryReader { geometry in
Colour.clear
.onAppear {
measurement = getTotalSize(geometry: geometry)
print("onAppear Dimension: (measurement)")
}
.onChange(of: geometry.measurement) { _ in
measurement = getTotalSize(geometry: geometry)
print("onChange Dimension: (measurement)")
}
}
)
// }
}
}
extension View {
func contentSize(measurement: Binding) -> some View {
return modifier(ContentSizeViewModifier(measurement: measurement))
}
func screenSize(measurement: Binding) -> some View {
return modifier(ScreenSizeViewModifier(measurement: measurement))
}
}
#Preview {
ContentView()
}
Can anybody please attempt clarify each challenge root trigger and answer for it?
Is there a greater or extra dependable method to calculate the view measurement with out manually including safeAreaInsets to geometry.measurement?
Moderator, please don’t deal with this query as associated to all points; it pertains to a single query solely”?