SwiftUI键盘工具栏内嵌ScrollView致导航栏标题卡住问题
问题说明
使用SwiftUI进行iOS开发时,若为键盘配置的toolbar(工具栏,对应ToolbarItem的.keyboard放置位置)内部嵌套ScrollView组件,会触发导航栏标题显示异常:标题会固定卡在屏幕对应位置,无法随导航栏正常联动移动、完成大标题折叠等布局效果。
该问题在Xcode 13.4.1环境下可稳定复现,最小复现代码如下:
struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State var numbers = Array(1...100).map { String($0) } var body: some View { NavigationView { List($numbers, id: \.self) { $number in TextField("", text: $number) } .toolbar { ToolbarItem(placement: .keyboard) { ScrollView(.horizontal) { HStack { Text("Hello") Text("World") } } } } .navigationTitle("Messed up title") } } }
异常效果参考:
解决方案
该问题属于SwiftUI的系统级布局冲突bug:键盘工具栏内的原生ScrollView会错误干扰导航栏的全局坐标计算,导致标题布局失效,目前有3种可落地的修复方案:
- 方案1:禁用工具栏内ScrollView的弹性效果
针对包含在工具栏内的UIScrollView,在视图出现时关闭其弹跳属性,即可消除布局冲突,代码修改如下:
该方案仅对UIToolbar内的滚动视图生效,不会影响页面其他位置的ScrollView效果,适配iOS 15及以上系统。ToolbarItem(placement: .keyboard) { ScrollView(.horizontal) { HStack { Text("Hello") Text("World") } } .onAppear { UIScrollView.appearance(whenContainedInInstancesOf: [UIToolbar.self]).bounces = false } } - 方案2:显式指定ScrollView及内容的固定高度
给ScrollView和其内部容器设置和系统键盘工具栏一致的固定高度(默认44pt),避免ScrollView动态计算高度时向上传递错误的布局值,代码修改如下:
该方案兼容性覆盖iOS 14及以上系统,缺点是需要手动匹配不同系统版本下键盘工具栏的默认高度。ToolbarItem(placement: .keyboard) { ScrollView(.horizontal) { HStack { Text("Hello") Text("World") } .frame(height: 44) } .frame(height: 44) } - 方案3:用UIKit封装的滚动组件替代SwiftUI原生ScrollView
通过UIViewRepresentable包装UIKit的UIScrollView实现横向滚动能力,从根源上避开SwiftUI ScrollView的布局逻辑冲突,适合对适配要求高、需要兼容低版本的场景。
内容的提问来源于stack exchange,提问作者Peter Warbo
相关产品推荐
相关产品推荐

