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

SwiftUI 3.0 iOS15 自定义TextFieldStyle键盘避让底部元素被遮挡问题

问题原因

SwiftUI 默认的键盘避让逻辑仅计算 TextField 原生输入区域的高度,不会纳入 TextFieldStyle 中自定义的下划线、错误提示等额外元素的高度,因此会出现组件底部内容被遮挡的问题。

解决方案

下面提供两种常用的实现方式,可根据你的业务场景选择:

方案1:添加底部内边距(最简单,适合样式高度固定的场景)

直接给每个 TextField 添加底部内边距,把自定义样式里额外的高度提前预留出来,系统计算避让高度时会自动纳入这部分padding的数值。
示例代码:

TextField(text: $firstNameText) {
    Text(.firstNameLabel)
}
.textFieldStyle(.customTextfieldStyle())
// 数值根据你自定义样式的最大高度调整,比如包含1行错误提示时总预留30px即可
.padding(.bottom, 30)

方案2:ScrollViewReader手动滚动(更精准,适合错误提示高度不固定的场景)

通过监听输入框聚焦状态和键盘弹出事件,手动控制滚动位置,确保整个自定义组件完全展示在可视区域内。

实现步骤:

  1. 定义聚焦字段枚举,绑定输入框的聚焦状态
  2. 给每个输入框设置唯一id
  3. 嵌套ScrollViewReader,在键盘弹出时滚动到对应输入框的底部位置

完整示例代码:

// 定义聚焦字段枚举
enum FocusField: Hashable {
    case firstName, lastName
}

struct SignupView: View {
    @State private var firstNameText = ""
    @State private var lastNameText = ""
    // 绑定当前聚焦的输入框
    @FocusState private var focusedField: FocusField?
    // 存储键盘高度
    @State private var keyboardHeight: CGFloat = 0
    
    var body: some View {
        VStack {
            ScrollViewReader { proxy in
                ScrollView {
                    VStack(spacing: 24) {
                        TextField(text: $firstNameText) {
                            Text(.firstNameLabel)
                        }
                        .textFieldStyle(.customTextfieldStyle())
                        .focused($focusedField, equals: .firstName)
                        .id(FocusField.firstName)
                        
                        TextField(text: $lastNameText) {
                            Text(.lastNameLabel)
                        }
                        .textFieldStyle(.customTextfieldStyle())
                        .focused($focusedField, equals: .lastName)
                        .id(FocusField.lastName)
                    }
                    .padding(.bottom, keyboardHeight)
                }
                // 监听键盘弹出事件,滚动到对应输入框
                .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
                    guard let focusedField = focusedField,
                          let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
                        return
                    }
                    keyboardHeight = keyboardFrame.height
                    withAnimation {
                        // 滚动到聚焦输入框的底部,额外留出边距避免贴边
                        proxy.scrollTo(focusedField, anchor: .bottom)
                    }
                }
                // 监听键盘收起事件,重置底部边距
                .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
                    keyboardHeight = 0
                }
            }
            Spacer()
            Button(action: submit) {
                Text(.nextButtonTitle)
            }
        }
    }
    
    func submit() {
        // 提交逻辑
    }
}

注意:如果你的页面底部固定按钮也需要避让键盘,可以给按钮也添加对应高度的底部内边距即可。

内容的提问来源于stack exchange,提问作者Antonio Chan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 11:24:04