I am developing a SwiftUI interface that aims to replicate a particular Apple-style navigation bar, where the title is positioned directly above a segmented picker, and both elements share a translucent background (using .thinMaterial
). This design allows the content of the view below to be visible through the navigation bar as it scrolls.
However, I’m encountering an issue where using the .principal
toolbar placement removes the inline title and positions the picker between the leading and trailing toolbar items, rather than below all these elements.
As you can see, Apple do it perfectly here:
import SwiftUI
struct TestView: View {
@State private var selectedView = 0
let pickerOptions = ["First View", "Second View"]
var body: some View {
NavigationView {
VStack(spacing: 0) {
Group {
if selectedView == 0 {
FirstView()
} else {
SecondView()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
.navigationBarTitle("Title", displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {}) {
Image(systemName: "ellipsis.circle")
}
}
ToolbarItem(placement: .principal) {
Picker("", selection: $selectedView) {
ForEach(pickerOptions.indices, id: .self) { index in
Text(self.pickerOptions[index]).tag(index)
}
}
.pickerStyle(SegmentedPickerStyle())
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {}) {
Image(systemName: "pencil.tip.crop.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 35)
Image(systemName: "person.crop.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 35)
}
.foregroundStyle(.white)
}
}
.background(.thinMaterial)
}
}
}
My goal is to adjust the placement so that the picker is situated directly below the title within the navigation bar, all while maintaining a clear visual pathway to the content behind through the translucent navigation bar equipment. How can I achieve this layout in SwiftUI?
I attempted to integrate the picker within the navigation bar by placing it in the .principal
section of the toolbar. My expectation was that this would allow the picker to appear just below the navigation title, still within the navigation bar area, to create a unified appearance as seen in Apple’s interfaces.
What I Was Expecting:
I expected the picker to align directly below the navigation title, forming a seamless continuation of the navigation bar. The goal was for the picker and the title to both have a thin, translucent material design, allowing the content scrolling behind them to be visible, enhancing the user interface’s aesthetic and functionality.
What Happened Instead:
Instead of the picker aligning below the title, using .principal
placement led to the picker being positioned between the leading and trailing toolbar items. This not only disrupted the expected layout but also removed the inline display of the navigation title, contrary to my goal of a seamless integration similar to Apple’s design.
cxrterz is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
4
In @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
You can use safeAreaInset
.safeAreaInset(edge: .top, content: {
Picker("", selection: $selectedView) {
ForEach(pickerOptions.indices, id: .self) { index in
Text(self.pickerOptions[index]).tag(index)
}
}
.pickerStyle(SegmentedPickerStyle())
})
1