SwiftUI自定义导航栏ToolbarItem二级页面截断问题求助
SwiftUI 自定义大尺寸导航栏跳转后被截断问题
问题背景
应用页面流转开发中,因需求要求导航栏尺寸大于系统默认尺寸,编写了自定义导航栏组件嵌入toolbar中使用。仅在应用落地页配置了NavigationView,全应用内页面跳转通过NavigationLink实现。
问题表现
- 流程首个页面的导航栏初始显示效果符合预期
- 跳转到第二个页面时,自定义导航栏会先正常显示极短时间,随即被截断
- 从第二个页面返回首个页面时,首页原本正常的导航栏也会出现截断问题
效果参考截图:

现有实现代码
自定义导航栏组件
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> var btnBack : some View { Button(action: { self.presentationMode.wrappedValue.dismiss() }, label: { HStack { Image("Left_Chevron") .aspectRatio(contentMode: .fit) .foregroundColor(.white) } }) } var navTitle = LocalizedStringKey("") var navSubtitle = LocalizedStringKey("") var body: some View { VStack(spacing: 5) { Spacer() btnBack .frame(maxWidth: .infinity, alignment: .leading) .padding(.top, 50) .offset(x: -5) Text(navTitle) .foregroundColor(.white) .font(.custom("Barlow-SemiBold", size: 24)) .frame(maxWidth: .infinity, alignment: .leading) .padding(.bottom, 4) Text(navSubtitle) .foregroundColor(Color(UIColor(red: 0.796, green: 0.796, blue: 0.796, alpha: 1))) .font(.custom("Barlow-Regular", size: 16)) .frame(maxWidth: .infinity, alignment: .leading) .padding(.bottom) } .frame(maxWidth: .infinity, maxHeight: .infinity) }
页面中调用自定义导航栏示例
var body: some View { ZStack(alignment: .top) { VStack { CommonTextfield(fieldTxt: $fieldTxt, placeholder: "Email Address") .padding(.bottom, 150) PrimaryButtonMed(destination: VerifyEmailView(), btnTitle: "reset_password") .padding(.trailing, -180) .opacity(validator.validateEmail(email: fieldTxt) ? 1 : 0.6) .disabled(!validator.validateEmail(email: fieldTxt)) Spacer() } .padding() .background(Color.black.opacity(0.9)) .ignoresSafeArea(.all, edges: .bottom) .navigationBarHidden(false) .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .navigationBarLeading) { NavigationViewToolBar(navTitle: "reset_password", navSubtitle: "reset_password_desc") } } } }
导航栏全局初始化配置
init() { navAppearance.configureWithTransparentBackground() navAppearance.backgroundColor = .black.withAlphaComponent(0.8) navAppearance.titleTextAttributes = [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 80)] navAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 80)] UINavigationBar.appearance().tintColor = .white UINavigationBar.appearance().standardAppearance = navAppearance UINavigationBar.appearance().scrollEdgeAppearance = navAppearance }
问题原因
系统UINavigationBar的ToolbarItem承载区有固定高度约束,不会根据放入的自定义视图尺寸自动撑开。当前自定义导航栏设置了maxHeight: .infinity试图撑满父容器,同时叠加了50pt的顶部padding,首次进入页面时布局未完成系统校验,能短暂看到完整内容;一旦页面转场触发布局刷新,超出系统默认导航栏高度的内容就会被自动裁切,返回首页时转场动画同样会触发导航栏重新布局,因此首页导航栏也会出现截断。
可行解决方案
- 方案1(最稳定,推荐):完全隐藏系统导航栏,自定义导航栏作为普通视图布局
在所有参与跳转的页面添加.navigationBarHidden(true),直接将自定义导航栏组件放在页面ZStack的顶部层级,自行适配安全区边距、返回按钮逻辑,完全绕开系统导航栏的固定高度限制。该方案无系统版本兼容问题,适合自定义程度高、尺寸和系统默认导航栏差异较大的需求。 - 方案2:保留系统导航栏,修正布局冲突
删掉自定义导航栏组件里的Spacer()和.frame(maxWidth: .infinity, maxHeight: .infinity)属性,不要让自定义视图试图撑满ToolbarItem的容器,给组件设置明确的固定高度(比如.frame(height: 90)),同时将顶部padding调整为适配系统导航栏的合理值,避免内容超出系统导航栏的可视区域。 - 方案3:修改系统导航栏默认高度(不推荐,兼容风险高)
通过UINavigationBar的分类方法调整导航栏的默认高度,匹配自定义导航栏的尺寸,但是该方案需要处理不同iOS版本的适配、转场动画异常等问题,稳定性较差。
内容的提问来源于stack exchange,提问作者Niall Rooney
相关产品推荐
相关产品推荐

