Modifying the background of views built with NavigationStack and Lists in SwitfUI

48 Views Asked by At

NavigationtStack, combined with Lists and Sections makes building a native UI very easy in SwiftUI. Looking at Apple's own apps there are certain bits of flair which I am looking to achieve in my own app. Specifically by adding a background to the overall layout.

For reference, here are 3 of Apple's own apps with backgrounds behind what appears to be built with NavigationStack. When you scroll down the page, the title shrinks to the small navigation bar.

Cropped screenshot of the Apple Health App

The Apple Health app has a bloom/gradient backdrop that is static until a certain portion of the page has scrolled.

Cropped screenshot of Apple Sports

The Apple Sports app has a short gradient that does not appear to remain static at all (but hard to tell).

Cropped screenshot of the Apple Home app

The Apple Home app has an image that is a backdrop to the entire app.

What I have found with SwiftUI is that I can specifically change the colour of the navigation title area, either when shown in its entirety or when collapsed. This option only allows a solid colour, gradients or images cannot be applied.

When using ZStack I can stack a gradient behind the title section, but it then appears above the collapsed title when scrolling.

Trying to stack a rectangle and positioning higher up causes a visible separation between the rectangle and the following content (List in my case) which breaks the flow. The example below puts a rectangle with a gradient which is followed by a clear break before the NavigationStack is show. Using the position modifier only re-positions the rectangle in its own space.

Rectangle()
    .fill(LinearGradient(
        gradient: .init(colors: [.red, .blue]),
        startPoint: .init(x: 0, y: 0),
        endPoint: .init(x: 0, y: 1)
    ))
    .ignoresSafeArea()
    .frame(height: 50)
NavigationStack {
    List {
        Section("", content: {
            Text("First Item")
        })
    }
    .toolbar {
        Button("Add") {}
    }
    .navigationTitle("Page Test")
    .toolbarBackground(.pink, for: .navigationBar)
    .toolbarBackground(.visible, for: .navigationBar)
    .toolbarColorScheme(.dark, for: .navigationBar)
}

This is the output of the code:

Screenshot of vertically stacked elements in a Swift Playgrounds preview

The answer to a similar question points to placing ScrollView inside the Navigation Stack I encounter the same issue, just that the rectangle and List each take half of the screen and the NavigationStack title now sits on top of everything.

If I take the same code and wrap it in ScrollView instead, that causes the NavigationStack to appear off screen and it's inaccessible so you're left with a gradient on a blank screen.

Screenshot of predominantly blank Swift Playground preview

Wrapping with ZStack instead causes the gradient to be hidden behind the default background colour of the view. Rearranging so the rectangle is second causes it to sit above everything underneath it.

Screenshot of items stacked on top of each other in a Swift Playgrounds preview

Given the examples from Apple above, how can you customise a SwiftUI view that uses NavigationStack with either a defined colour, gradient or image as a background?

0

There are 0 best solutions below