I'm trying to wrap a content view inside a NavigationStack
. However, when I use NavigationStack
, the scale animation shows strange behavior and it does not ignore the safe area either (it works perfectly without NavigationStack
). I've already found a solution for the scale animation around the safe area (without NavigationStack
) here. SideMenuControllerView
serves as the parent view responsible for managing all animations related to the content view.
struct SideMenuControllerView<Content: View>: View {
@State private var scale = false
private var content: Content
init(content: Content) {
self.content = content
}
var body: some View {
ZStack {
content
.offset(x: 100)
.scaleEffect(scale ? 0.8 : 1)
.ignoresSafeArea()
Button {
withAnimation(.easeInOut(duration: 3)) {
scale.toggle()
}
} label: {
Text("Scale")
}
.frame(maxWidth: .infinity,alignment: .leading)
.padding()
}
}
}
struct OrangeView: View {
@Binding var path: [String]
var body: some View {
NavigationStack(path: $path) { /// <- NOT wroking
OrangeViewContent()
}
//OrangeViewContent() /// <- works fine
}
}
struct OrangeViewContent: View {
var body: some View {
GeometryReader { proxy in
ZStack {
Color.orange
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{ Color.cyan }
}
}
}
}
#Preview {
SideMenuControllerView(
content: OrangeView(path: .constant([]))
)
}
The modifiers for transformation and ignoring safe area need to be applied directly to OrangeViewContent
. So now that this content is surrounded by a NavigationStack
, it means moving the modifiers into OrangeView
and passing the boolean flag as a parameter to this view.
Like this:
struct ContentViewTest: View {
@State private var scale = false
var body: some View {
ZStack {
OrangeView(path: .constant([]), scale: scale)
Button {
withAnimation(.easeInOut(duration: 3)) {
scale.toggle()
}
} label: {
Text("Scale")
}
.frame(maxWidth: .infinity,alignment: .leading)
.padding()
}
}
}
struct OrangeView: View {
@Binding var path: [String]
let scale: Bool
var body: some View {
NavigationStack(path: $path) {
OrangeViewContent()
.offset(x: 100)
.scaleEffect(scale ? 0.8 : 1)
.ignoresSafeArea()
}
}
}
EDIT Following from your comments, I tried quite hard to find a way to avoid having to move the modifiers inside the NavigationStack
, but I couldn't get it to work. So the best I can suggest is that you pass the Bool
as a Binding
to SideMenuControllerView
(where it is controlled), so that it can also be passed as a let
constant to the underlying content view (where it is used, as per my answer above). The parent container would then look something like this:
@State private var scale = false
var body: some View {
SideMenuControllerView(
scale: $scale,
content: OrangeView(path: .constant([]), scale: scale)
)
}