SwiftUI兼容iOS14:选择DatePicker后使TextField失去焦点
DatePicker与TextField双向同步焦点异常解决方案(兼容iOS14)
问题表现
已实现DatePicker和TextField的基础双向绑定:
- DatePicker选择日期时,TextField内容同步更新
- TextField手动输入日期时,DatePicker选中值同步更新
存在异常:TextField输入后保持焦点状态时,点击DatePicker选择日期,TextField不会失焦,内容也不会随DatePicker选择同步更新。
因项目需要兼容iOS14,无法使用iOS15+才支持的@FocusState处理焦点。
问题效果演示:
问题根源
TextField处于编辑状态时,点击graphical样式的DatePicker区域,系统不会自动触发输入框的第一响应者释放,持有焦点的TextField会阻塞$selectedDate的绑定刷新逻辑,导致UI不同步。
兼容实现方案
直接复用已实现的UIApplication.endEditing()全局收键盘扩展,给DatePicker添加同步手势响应,点击DatePicker时主动让TextField失焦即可,不需要引入额外依赖:
- 给DatePicker添加
simultaneousGestureTap手势,点击时主动调用收键盘方法,选择同时识别手势是为了不覆盖DatePicker本身的日期选择事件 - 可选添加
onChange监听selectedDate变化做兜底,覆盖部分iOS14小版本下手势识别失效的边缘场景
修改后完整代码
import SwiftUI import Combine struct ContentView: View { @State private var selectedDate = Date() @State private var isHidden = true let formatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "MM/dd/yyyy" return formatter }() var body: some SwiftUI.View { VStack(alignment: .center) { ZStack { HStack(alignment: .center) { Text("Start Date") .frame(maxWidth: .infinity, alignment: .leading) .background(Color.yellow) .onTapGesture { self.onExpandTapped() } Spacer() .background(Color.yellow) if isHidden { Text(selectedDate, style: .date) .onTapGesture { self.onExpandTapped() } } else { TextField("Date", value: $selectedDate, formatter: formatter) .multilineTextAlignment(.trailing) .background(Color.red) .fixedSize() } } } if !isHidden { DatePicker("", selection: $selectedDate, displayedComponents: .date) .padding(.horizontal) .frame(width: 333) .datePickerStyle(.graphical) .labelsHidden() // 点击DatePicker时主动收起键盘 .simultaneousGesture( TapGesture().onEnded { _ in UIApplication.shared.endEditing() } ) // 兜底逻辑,日期变更时确保输入框失焦 .onChange(of: selectedDate) { _ in UIApplication.shared.endEditing() } } } } private func onExpandTapped() { isHidden.toggle() UIApplication.shared.endEditing() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } extension UIApplication { func endEditing() { sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } }
效果说明
修改后,只要点击DatePicker区域就会主动释放TextField的焦点,绑定逻辑恢复正常,选日期时TextField内容可以实时同步更新,方案完全兼容iOS14及以上系统版本。
内容的提问来源于stack exchange,提问作者Atlantis
相关产品推荐
相关产品推荐

