The view below is pushed on NavigationStack. My main point is to have a top bar view, with a background expanding under nav bar, the top bar should have a shadow below, and below is a ScrollView with some content.
struct ContentView: View {
var body: some View {
VStack (spacing: 0) {
HStack {
Text("Title")
}
.frame(maxWidth: .infinity)
.padding()
.background(.red)
.compositingGroup()
.shadow(color: .black, radius: 5)
.zIndex(1)
ScrollView {
VStack(spacing: 0) {
ForEach((1...100), id: \.self) {
Text("\($0)…")
.frame(maxWidth: .infinity)
.background(.white)
}
}
}
}
}
}
To make the shadow, applied to title view, visible, I had to change the view zIndex to 1, so that the shadow is drawn above scroll view content. It works fine, but have a very weird side effect. With this code, when the scroll view starts scrolling, the color of the nav bar changes, see below.
If I don't change the zIndex of the title bar, there is no effect like this, but the shadow is not visible.
I was able to reproduce this problem when the view is shown as a child view of a NavigationStack
.
The red is extending to the top of the screen because it is in contact with the safe area and the .background
modifier that you are using ignores safe areas by default - see background(_:ignoresSafeAreaEdges:). However, the navigation bar is still being shown over your red background, which is why the Back button is also visible.
When the content is scrolled up behind the navigation bar, the background of the navigation bar changes to a Material
effect, so you see the lighter color. As you pointed out, this seems to be exceptional behavior due to setting zIndex
on the content in that part of the screen.
Here are two ways to prevent it happening:
1. Hide the background behind the navigation bar
This is done by applying .toolbarBackground(.hidden, for: .navigationBar)
to the VStack
:
var body: some View {
NavigationStack {
NavigationLink("show child") {
VStack(spacing: 0) {
// content as in your example
}
.toolbarBackground(.hidden, for: .navigationBar) // <- ADDED
}
}
}
2. Fill the base layer
The problem doesn't happen if you use a ZStack
and fill the base layer (the layer below the header and the scrolled content):
var body: some View {
NavigationStack {
NavigationLink("show list") {
ZStack {
Color.red
VStack(spacing: 0) {
// content as in your example
}
}
}
}
}