iOS 16中NavigationStack返回时父视图大标题变行内的解决问询
在iOS 16环境下,使用Xcode 14 Beta 6开发SwiftUI应用时,出现以下问题:从设置为.inline标题显示模式的页面返回后,原本设置为.large大标题模式的SettingsView会自动变为行内模式,用户需要滚动页面才能恢复原大标题模式。该问题在预览中未出现,但在iOS 16模拟器中存在。将NavigationStack替换为NavigationView可解决此问题,但苹果已宣布NavigationView在iOS 16中废弃,现咨询如何确保SettingsView的大标题始终显示。
SettingsView 代码
struct SettingsView: View { @State private var isPresentingChangePasswordView = false var body: some View { Form { Section { NavigationLink(destination: EmptyView()) { Label("Account Details", systemImage: "person") } NavigationLink { Form { Button("Change Password") { isPresentingChangePasswordView = true } } .navigationTitle("Password & Security") .navigationBarTitleDisplayMode(.inline) } label: { Label("Password & Security", systemImage: "lock") } NavigationLink(destination: EmptyView()) { Label("Manage Subscription", systemImage: "crown") } Button { } label: { HStack { Label { Text("Sign Out") .foregroundColor(.black) } icon: { Image(systemName: "rectangle.portrait.and.arrow.right") } Spacer() Image(systemName: "chevron.forward") .foregroundColor(Color(red: 191/255, green: 191/255, blue: 191/255)) .fontWeight(.semibold) .imageScale(.small) } } } header: { Text("Your account") } } .navigationTitle("Settings") .navigationBarTitleDisplayMode(.large) .sheet(isPresented: $isPresentingChangePasswordView) { ChangePasswordView() } } }
HomeView 代码
struct HomeView: View { var body: some View { NavigationStack { Text("HomeView") .toolbar { NavigationLink(destination: SettingsView()) { Image(systemName: "gearshape") .foregroundColor(.gray) } } .navigationTitle("Home") } } }
更新说明
将NavigationStack替换为NavigationView时,功能符合预期,但苹果已宣布NavigationView在iOS 16中废弃。
解决方案
1. 强制在SettingsView的onAppear中重置标题显示模式
利用UIKit的API强制设置导航栏为大标题模式,修复SwiftUI导航栈回退时的状态异常:
struct SettingsView: View { @State private var isPresentingChangePasswordView = false var body: some View { Form { // 原Form内容保持不变 } .navigationTitle("Settings") .navigationBarTitleDisplayMode(.large) .onAppear { UINavigationController.appearance().navigationBar.prefersLargeTitles = true } .sheet(isPresented: $isPresentingChangePasswordView) { ChangePasswordView() } } }
注意:如果App内有其他页面需要使用inline标题,需在对应页面的onAppear中设置prefersLargeTitles = false,避免全局影响。
2. 改用NavigationStack的navigationDestination管理跳转
NavigationStack推荐使用navigationDestination来统一管理页面跳转,这种方式能更稳定地维护导航栈状态,减少标题模式异常:
修改HomeView:
struct HomeView: View { @State private var showSettings = false var body: some View { NavigationStack { Text("HomeView") .toolbar { Button { showSettings = true } label: { Image(systemName: "gearshape") .foregroundColor(.gray) } } .navigationTitle("Home") .navigationDestination(isPresented: $showSettings) { SettingsView() } } } }
后续SettingsView内的跳转也建议采用navigationDestination方式,结构化的跳转逻辑能降低状态异常概率。
3. 升级Xcode版本
该问题是Xcode 14 Beta版本的已知bug,苹果在后续的正式版及更新Beta版本中已修复此问题。直接升级到Xcode 14正式版或更高版本,无需修改代码即可解决问题。
内容的提问来源于stack exchange,提问作者Jack Rogers

