I'm attempting to resize a view, but when the view (YellowView) enlarges/shrinks to the safe area, all elements within the view experience a sudden shift (caused by the change in view size). How would you recommend addressing this issue to prevent the abrupt movement?
import SwiftUI
struct ContentView: View {
@State private var scale = false
var body: some View {
GeometryReader { proxy in
ZStack {
YellowView()
.ignoresSafeArea()
.offset(x: 100)
.scaleEffect(scale ? 0.8 : 1)
Button {
withAnimation(.easeInOut(duration: 3)) {
scale.toggle()
}
} label: {
Text("Scale")
}
.frame(maxWidth: .infinity,alignment: .leading)
.padding()
}
}
}
}
struct YellowView: View {
var body: some View {
ZStack {
HStack {
Text("TopBar")
.frame(maxWidth: .infinity)
.background(Color.gray)
}
.frame(maxWidth: .infinity,maxHeight: .infinity, alignment: .top)
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.black)
Text("Hello, world!")
}
.padding()
.background(.cyan)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.yellow)
}
}
#Preview {
ContentView()
}
First, you should apply .ignoreSafeArea
after applying the scale effect:
YellowView()
.offset(x: 100)
.scaleEffect(scale ? 0.8 : 1)
.ignoresSafeArea()
After this you should see that the animation is a bit smoother, but the background fills still jump from "filling the whole safe area" to "not filling any of the safe area". This is because background
tries to fill the entire safe area by default.
To disable that, pass an empty set to the ignoresSafeAreaEdges
argument.
struct YellowView: View {
var body: some View {
ZStack {
HStack {
Text("TopBar")
.frame(maxWidth: .infinity)
.background(.gray, ignoresSafeAreaEdges: [])
}
.frame(maxWidth: .infinity,maxHeight: .infinity, alignment: .top)
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.black)
Text("Hello, world!")
}
.padding()
.background(.cyan, ignoresSafeAreaEdges: [])
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.yellow, ignoresSafeAreaEdges: [])
}
}
Alternatively, you can use the overload of background
that takes a ViewBuilder
closure. This overload doesn't ignore the safe area by default. e.g.
.background { Color.yellow }