iOS 26+中Large Navigation Title随ScrollView异常滚动问题求解决方案
问题复现代码
struct ContentView: View { var body: some View { NavigationStack { VStack { Rectangle() .foregroundStyle(.red) .frame(width: 100, height: 100) ScrollView { Text("Text") Text("Text2") Text("Text3") } } .navigationTitle("Large Title") .toolbarTitleDisplayMode(.large) } } }
从iOS 16开始,无论ScrollView在视图层级中的哪个位置,滚动它都会触发Large Navigation Title的收缩/展开交互。当ScrollView位于屏幕底部时,这种联动会导致布局异常,属于系统已知行为Bug。
可行解决办法
方法1:iOS 17+ 原生API快速解决
iOS 17引入了scrollBehavior修饰符,直接设置为.static即可解除ScrollView与导航栏的滚动联动:
ScrollView { Text("Text") Text("Text2") Text("Text3") } .scrollBehavior(.static)
方法2:iOS 16兼容方案(自定义ScrollView)
如果需要兼容iOS 16,可以通过UIViewRepresentable封装一个不触发导航栏交互的ScrollView:
struct NonNavScrollView<Content: View>: UIViewRepresentable { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } func makeUIView(context: Context) -> UIScrollView { let scrollView = UIScrollView() // 禁用自动调整contentInset,避免触发导航栏联动 scrollView.contentInsetAdjustmentBehavior = .never let hostingView = UIHostingController(rootView: content) hostingView.view.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(hostingView.view) NSLayoutConstraint.activate([ hostingView.view.topAnchor.constraint(equalTo: scrollView.topAnchor), hostingView.view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), hostingView.view.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), hostingView.view.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), hostingView.view.widthAnchor.constraint(equalTo: scrollView.widthAnchor) ]) return scrollView } func updateUIView(_ uiView: UIScrollView, context: Context) { guard let hostingView = uiView.subviews.first as? UIHostingController<Content> else { return } hostingView.rootView = content } }
使用时替换原有的ScrollView:
struct ContentView: View { var body: some View { NavigationStack { VStack { Rectangle() .foregroundStyle(.red) .frame(width: 100, height: 100) NonNavScrollView { Text("Text") Text("Text2") Text("Text3") } } .navigationTitle("Large Title") .toolbarTitleDisplayMode(.large) } } }
方法3:全局修改ScrollView行为(谨慎使用)
如果你的App中所有ScrollView都不需要触发导航栏联动,可以在App结构体中全局设置:
@main struct YourApp: App { init() { UIScrollView.appearance().contentInsetAdjustmentBehavior = .never } var body: some Scene { WindowGroup { ContentView() } } }
注意:此方法会影响所有ScrollView,包括那些原本需要联动导航栏的场景,需谨慎使用。
内容的提问来源于stack exchange,提问作者MegaManX
相关产品推荐
相关产品推荐

