Hi,
I'm experiencing a layout issue in SwiftUI when using TabView
, NavigationStack
, and a List
in a specific navigation flow. Here's how to reproduce it:
- Tap on Tab 3.
- Tap "Tap Me to go to the subview" to navigate to the detail view.
- In the detail view, tap Back to return to Tab 3.
- Tap "Tap Me to go to the subview" again.
Problem: When returning to the detail view, the content (especially the List) appears incorrectly positioned within the safe area, as if it's overlapping or misaligned with the navigation bar. This happens only when navigating back and forth after dismissing a sheet presented from a different tab.
This animated gif shows the workflow to visualize the problem:
Expected Behavior: The content should consistently respect the safe area and be positioned correctly under the navigation bar.
Thanks in advance for your help!
Here is the complete code to reproduce the issue:
import SwiftUI
@Observable
class MenuSelector {
var initialIndex: Int
var customTabIndex: Int
var isCustomTabSelected: Bool = false
private var previousIndex: Int
init(customTabIndex: Int, initialIndex: Int = 0) {
self.initialIndex = initialIndex
self.customTabIndex = customTabIndex
self.itemSelected = initialIndex
self.previousIndex = initialIndex
}
var itemSelected: Int {
didSet {
if itemSelected == customTabIndex {
previousIndex = oldValue
itemSelected = oldValue
isCustomTabSelected = true
}
}
}
}
struct NavigationStackSpikeView: View {
@State private var tabSelector = MenuSelector(customTabIndex: 1)
var body: some View {
TabView(selection: $tabSelector.itemSelected) {
Text("Tab 1")
.tabItem {
Text("Tab 1")
}
.tag(0)
Text("I want to present a sheet for this tab")
.tabItem {
Text("Action")
}
.tag(1)
Tab3View()
.tabItem {
Text("Tab 3")
}
.tag(2)
}
.sheet(isPresented: $tabSelector.isCustomTabSelected) {
SheetView()
}
}
}
struct Tab3View: View {
@State private var navigationPath = NavigationPath()
var body: some View {
NavigationStack(path: $navigationPath) {
VStack {
NavigationLink(value: Destination.subview) {
Text("Tap Me to go to the subview")
}
}
.navigationDestination(for: Destination.self) { destination in
switch destination {
case .subview:
DetailView()
}
}
}
}
enum Destination: Hashable {
case subview
}
}
struct DetailView: View {
var body: some View {
VStack {
List {
Text("A detail")
}
.listStyle(.plain)
}
.navigationTitle("Details")
.navigationBarTitleDisplayMode(.inline)
}
}
struct SheetView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
Text("I'm a sheet")
Button("Dismiss") { dismiss() }
}
}
}
#Preview {
NavigationStackSpikeView()
}