SwiftUI底部Toolbar被键盘系统辅助视图遮挡问题求助(Xcode 12.4/iOS 14)
解决iOS14 SwiftUI Form底部Toolbar被键盘辅助视图遮挡的问题
嘿,我之前在iOS14的SwiftUI项目里碰到过一模一样的问题!这是iOS14版本里SwiftUI原生底部Toolbar的一个已知适配bug——当键盘唤起(尤其是带预测输入栏的时候),系统没法正确处理.bottomBar位置Toolbar的安全区域偏移,导致它被键盘的辅助视图挡住。
下面给你两个实用的解决方案,你可以根据需求选择:
方案一:改用自定义底部工具栏(最可靠)
放弃原生的.bottomBar Toolbar,改用自定义的底部视图嵌套在根VStack里,这样它会自动响应键盘的安全区域变化,完美避让键盘。
修改后的代码如下:
struct ContentView: View { @State var narrative: String = "" var body: some View { VStack(spacing: 0) { NavigationView { Form { Section(header: Text("Test 1")) { Text("Bla Bla Bla") } Section(header: Text("Test 2")) { Text("Bla Bla Bla") } Section(header: Text("Test 3")) { Text("Bla Bla Bla") } Section(header: Text("Test 4")) { Text("Bla Bla Bla") } Section(header: Text("Test 5")) { Text("Bla Bla Bla") } Section(header: Text("Text Editor 1")) { TextEditor(text: $narrative) } Section(header: Text("Test 6")) { Text("Bla Bla Bla") } Section(header: Text("Test 7")) { Text("Bla Bla Bla") } Section(header: Text("Test 8")) { Text("Bla Bla Bla") } Section(header: Text("Test 9")) { Text("Bla Bla Bla") TextEditor(text: $narrative) } } .navigationTitle("Title") .navigationBarTitleDisplayMode(.inline) } .navigationViewStyle(StackNavigationViewStyle()) // 自定义底部工具栏,模拟原生样式 HStack { Spacer() Button("Press me") { // 你的按钮逻辑 } .padding(.vertical, 12) Spacer() } .background(Color(UIColor.systemBackground)) .border(Color(UIColor.separator), edge: .top) } } } // 扩展View,给指定边缘添加边框 extension View { func border(_ color: Color, edge: Edge, lineWidth: CGFloat = 1) -> some View { overlay(EdgeBorder(color: color, edge: edge, lineWidth: lineWidth)) } } struct EdgeBorder: Shape { var color: Color var edge: Edge var lineWidth: CGFloat func path(in rect: CGRect) -> Path { switch edge { case .top: return Path([CGPoint(x: rect.minX, y: rect.minY), CGPoint(x: rect.maxX, y: rect.minY)]) case .bottom: return Path([CGPoint(x: rect.minX, y: rect.maxY), CGPoint(x: rect.maxX, y: rect.maxY)]) case .leading: return Path([CGPoint(x: rect.minX, y: rect.minY), CGPoint(x: rect.minX, y: rect.maxY)]) case .trailing: return Path([CGPoint(x: rect.maxX, y: rect.minY), CGPoint(x: rect.maxX, y: rect.maxY)]) } } }
这个方案完全避开了原生Toolbar的bug,自定义视图会自动跟随键盘上移,视觉样式也能和原生Toolbar保持一致。
方案二:监听键盘高度动态调整Toolbar内边距
如果你一定要用原生的.bottomBar Toolbar,可以通过监听键盘高度,动态给Toolbar添加底部内边距来避让键盘:
首先添加一个监听键盘高度的ViewModifier:
import Combine extension View { func adjustForKeyboard() -> some View { modifier(KeyboardAdjustmentModifier()) } } struct KeyboardAdjustmentModifier: ViewModifier { @State private var keyboardHeight: CGFloat = 0 private var keyboardPublisher: AnyPublisher<CGFloat, Never> { Publishers.Merge( NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification) .map { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero } .map { $0.height }, NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification) .map { _ in 0 } ) .eraseToAnyPublisher() } func body(content: Content) -> some View { content .padding(.bottom, keyboardHeight) .onReceive(keyboardPublisher) { height in withAnimation { self.keyboardHeight = height } } } }
然后给你的Toolbar所在的Form添加这个modifier:
Form { // 你的Form内容不变 } .navigationTitle("Title") .navigationBarTitleDisplayMode(.inline) .toolbar(content: { ToolbarItem(placement: .bottomBar) { Button("Press me") { } } }) .adjustForKeyboard() // 添加这个modifier
这个方案通过监听键盘的显示/隐藏通知,动态调整视图的底部内边距,让Toolbar避开键盘区域。
内容的提问来源于stack exchange,提问作者pprochazka72
相关产品推荐
相关产品推荐

