I'm currently working on an app for watchOS, but this problem is the same on iOS.
When I use ignoring the bottom edge of the safe area for a view that is slightly larger than the safe area, the layout breaks, as if ignoring the bottom edge of the safe area did not work.
The desired result was obtained only by using GeometryReader
. But I wouldn't want to use an expensive GeometryReader
in cases where I don't need the geometry and when it should work without it.
Could someone explain why this problem occurs and how to avoid it without using a workaround with GeometryReader
?
Here's the demo code for the watchOS app where the ProblemView
reproduces the problem I described, and the FixedView
works as it should.
The heights in the code is specified to reproduce this problem on the Apple Watch Ultra (49 mm) or its simulator.
import SwiftUI
struct ContentView: View {
var body: some View {
// You can comment/uncomment one of the views to check it out.
ProblemView()
// FixedView()
}
}
struct ProblemView: View {
var body: some View {
HigherThanSafeAreaView()
.ignoresSafeArea(edges: .bottom)
}
}
struct FixedView: View {
var body: some View {
GeometryReader { _ in
HigherThanSafeAreaView()
}
.ignoresSafeArea(edges: .bottom)
}
}
struct HigherThanSafeAreaView: View {
var body: some View {
// Apple Watch Ultra (49mm) has a total screen height of 251 points.
// The height of the safe area is 177 and the top and bottom insets are 37 each.
//
// So, to go beyond the safe area but still fit on the screen,
// I put two rectangles in the VStack, each 100 points high.
// Between them I put a Spacer which should fill the free height.
// If we ignore the bottom edge of the safe area, the total size will be 214 points.
// Accordingly, it is expected that this Spacer will fill 14 points
// for the Apple Watch Ultra (49mm)
VStack(spacing: 0) {
Rectangle()
.frame(height: 100)
Spacer(minLength: 0)
Rectangle()
.foregroundColor(.gray)
.frame(height: 100)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice(.init(rawValue: "Apple Watch Ultra (49mm)"))
}
}
Unexpected result of ProblemView
:
The expected result achieved with FixedView
: