How the NavigationStack changed
How background colors affect the NavigationStack
How to set a custom background color for the NavigationStack
How scrolling a List affects the NavigationStack
How to customize the NavigationStack when scrolling
How to set a custom font for the NavigationStack
Completely replace the NavigationStack with a custom view using safeAreaInset
Bonus: Using ZStack for a NavigationStack background
Starting in iOS 15, the background materials for bars (navigation bar, tab bar, etc.) were removed "giving more visual clarity to your content" as stated in this WWDC 2021 video titled "What's new in UIKit".
When you set a background color, you will notice it will go behind the NavigationView for large and inline nav bars.
In SwiftUI, starting in iOS 15:
The background of a view, such as shape styles, will automatically expand into the safe areas it touches.
When I say "shape style", I'm talking about styles that conform to the ShapeStyle protocol, such as:
Materials (blur effects)
Hierarchical styles (secondary, tertiary, quaternary)
There is a new initializer introduced with iOS 15 that allows backgrounds to expand into safe areas. You could manually set the safe area edge but by default, it is set to "all" edges.
That Rectangle with the background HAS to touch the safe area edge.
The shape style (Color) is in a background modifier because the background accepts a "ShapeStyle" type.
The background touching the safe area edge should be the full width of the NavigationStack. The Rectangle shape expands horizontally to match the width of the device/NavigationStack.
You can use a Divider instead of a Rectangle. Let's combine it with a material this time:
This makes it look more like how NavigationStack used to look.
Gradients are also a ShapeStyle type.
A vertical gradient doesn't work too well using this method because only the top color will bleed into the safe area.
Instead, use a linear gradient with some angle besides a vertical one.
The Rectangle has a height and so it will add some padding to the bottom of the NavigationStack.
Because the Rectangle has height, I filled it with a clear color so you can see its background gradient.
When you scroll up a List, the NavigationStack will automatically turn into the inline style with a material background:
But as soon as you try to customize the NavigationStack, you lose this feature.
When you scroll up, the NavigationStack does not collapse inline. And the rows do not scroll behind the NavigationView.
For this to work, the List has to touch the NavigationStack.
So how can we customize the NavigationStack AND keep this behavior while scrolling?
You will need to use the UINavigationBarAppearance from UIKit to customize the NavigationStack and keep the behavior when scrolling.
With a UINavigationBarAppearance, you can customize all different aspects of the NavigationStack.
Sets a material (blur effect)
Sets a color
Assigns it to the scrollEdgeAppearance - Which you want to use when you have a scrollable view (like a List or ScrollView) touching the NavigationView.
Note: You can set these appearance properties in onAppear, the views init, or even in your App delegate when your app starts. It's up to you.
Here is the result:
Do you see the problem?
When the NavigationStack switched to inline (second screenshot), it lost the customizations!
The UINavigationBarAppearance allows you to customize different states or appearances of the NavigationStack.
So you need to apply the appearance you want to the standardAppearance of the NavigationStack:
Now it looks correct when scrolling up:
You will need the UINavigationBarAppearance again.
Notice you can set different fonts for large and inline titles:
If you don't want to go into UIKit land and use UINavigationBarAppearance then you can create your own navigation view.
Using safeAreaInset, you can easily add a view to a scrolling view (List, ScrollView) and have the list scroll behind your custom navigation view.
Don't forget to hide the NavigationStack (.navigationBarHidden(true)) when you add your own.
You learned you can customize the NavigationStack in SwiftUI with the use of ShapeStyles that are set as backgrounds to views touching the safe area edge of the NavigationStack.
You also learned how to use UINavigationBarAppearance for customizations.
Finally, you learned you can hide the NavigationStack and create your own with the use of the safeAreaInset modifier on a scrolling view.
Do you need a SwiftUI visual reference guide?
You can download the SwiftUI Views Quick Start Book for FREE to get you started.
Someone suggested using a ZStack and a separate shape style to create a background.
This is totally doable.
Here's how I did it:
You need to ignore the top safe area edge.
The frame height is ZERO in this example. Greater than zero will make it grow downward from the NavigationStack. Pretty interesting.
Create UI with SwiftUI Views Mastery (beginner)
Architect your app using Working with Data in SwiftUI (beginner)
Improve your app's UX with SwiftUI Animations Mastery (junior)
React to and manipulate data using Combine Mastery in SwiftUI (advanced)