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手动滚动(更精准,适合错误提示高度不固定的场景)
通过监听输入框聚焦状态和键盘弹出事件,手动控制滚动位置,确保整个自定义组件完全展示在可视区域内。
实现步骤:
- 定义聚焦字段枚举,绑定输入框的聚焦状态
- 给每个输入框设置唯一id
- 嵌套
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
相关产品推荐
相关产品推荐

