You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI返回父视图时navigationBarTitle无法从.inline恢复为.large

SwiftUI 导航栏标题模式无法自动恢复的问题解决办法

问题描述

在iOS16的模拟器或真机中,使用自定义Cancel按钮(通过@Environment(.dismiss))从子视图返回父视图时,父视图的导航栏标题无法自动从子视图的.inline模式恢复为原本设置的.large模式,只有下拉列表才会触发恢复;部分机型(如iPhone14Pro)还会出现模式切换动画生硬的情况,而Xcode Live Preview中该问题可能不会出现。

复现代码

struct ContentView: View {
    @State private var sheetIsPresented = false
    var items = ["Item1", "Item2", "Item3"]
    var body: some View {
        NavigationStack {
            List {
                ForEach(items, id: \.self) { item in
                    NavigationLink(item, destination: DestinationView(item: item))
                        .padding()
                }
            }
            .navigationBarTitle("Home", displayMode: .large)
            .listStyle(.plain)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        sheetIsPresented.toggle()
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        }
        .sheet(isPresented: $sheetIsPresented) {
            NavigationStack {
                DestinationView(item: "New!")
            }
        }
    }
}

struct DestinationView: View {
var item: String
@Environment(.dismiss) private var dismiss

var body: some View {
    List {
        Text(item)
    }
    .toolbar {
        ToolbarItem (placement: .navigationBarLeading) {
            Button("Cancel") {
                dismiss()
            }
        }
    }
    .listStyle(.plain)
    .navigationBarTitleDisplayMode(.inline)
    .navigationBarBackButtonHidden()
}
}

问题原因

这是SwiftUI导航栈状态同步的已知bug:当使用自定义返回按钮而非系统默认的导航返回按钮时,导航栏的标题模式状态没有正确回滚到父视图的配置,导致父视图标题模式异常。

解决方案

以下是几种可行的临时解决办法:

方法1:子视图消失时重置父视图标题模式

在父视图中通过状态变量控制标题模式,子视图消失时触发重置:

struct ContentView: View {
    @State private var sheetIsPresented = false
    @State private var titleDisplayMode: NavigationBarItem.TitleDisplayMode = .large
    var items = ["Item1", "Item2", "Item3"]
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(items, id: \.self) { item in
                    NavigationLink(item, destination: DestinationView(item: item)
                        .onDisappear {
                            titleDisplayMode = .large
                        })
                        .padding()
                }
            }
            .navigationBarTitle("Home", displayMode: titleDisplayMode)
            .listStyle(.plain)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        sheetIsPresented.toggle()
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        }
        .sheet(isPresented: $sheetIsPresented) {
            NavigationStack {
                DestinationView(item: "New!")
                    .onDisappear {
                        titleDisplayMode = .large
                    }
            }
        }
    }
}

方法2:使用NavigationPath手动管理导航栈

通过绑定导航路径,在自定义返回时手动更新栈状态,触发标题模式恢复:

struct ContentView: View {
    @State private var sheetIsPresented = false
    @State private var navigationPath = NavigationPath()
    var items = ["Item1", "Item2", "Item3"]
    
    var body: some View {
        NavigationStack(path: $navigationPath) {
            List {
                ForEach(items, id: \.self) { item in
                    NavigationLink(item, value: item)
                        .padding()
                }
            }
            .navigationDestination(for: String.self) { item in
                DestinationView(item: item, dismissAction: {
                    navigationPath.removeLast()
                })
            }
            .navigationBarTitle("Home", displayMode: .large)
            .listStyle(.plain)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        sheetIsPresented.toggle()
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        }
        .sheet(isPresented: $sheetIsPresented) {
            NavigationStack {
                DestinationView(item: "New!", dismissAction: {})
            }
        }
    }
}

struct DestinationView: View {
    var item: String
    var dismissAction: () -> Void
    @Environment(.dismiss) private var dismiss

    var body: some View {
        List {
            Text(item)
        }
        .toolbar {
            ToolbarItem (placement: .navigationBarLeading) {
                Button("Cancel") {
                    dismissAction()
                    dismiss()
                }
            }
        }
        .listStyle(.plain)
        .navigationBarTitleDisplayMode(.inline)
        .navigationBarBackButtonHidden()
    }
}

方法3:全局强制恢复大标题模式(不推荐,影响全局)

通过UIKit的API强制设置导航栏偏好,适合仅单一导航栈的场景:

struct ContentView: View {
    @State private var sheetIsPresented = false
    var items = ["Item1", "Item2", "Item3"]
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(items, id: \.self) { item in
                    NavigationLink(item, destination: DestinationView(item: item))
                        .padding()
                }
            }
            .navigationBarTitle("Home", displayMode: .large)
            .listStyle(.plain)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        sheetIsPresented.toggle()
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        }
        .onAppear {
            UINavigationBar.appearance().prefersLargeTitles = true
        }
        .sheet(isPresented: $sheetIsPresented) {
            NavigationStack {
                DestinationView(item: "New!")
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Gallaugher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 02:55:33