You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 03:02:38