Swift多条目提交时Inline DatePicker显示异常问题排查
iOS 14+ 内联日期选择器重复显示时被截断的问题解决
问题场景
在记录拜日式(suryanamaskar)次数的页面中,点击日期按钮弹出iOS 14+的inline样式日期选择器,首次显示正常,但添加新条目或再次点击日期按钮时,选择器会被截断无法正常显示;改用wheels样式则无此问题。
核心问题分析
- 全局Picker实例重复添加:代码中
datePicker是全局常量,每次调用showDatePicker()都会将同一个Picker实例重复添加到viewPicker中,导致视图层级混乱。 - 固定Frame适配失效:
inline样式日期选择器的高度是动态的,使用固定frame布局无法适配其真实高度,导致显示截断。 - Picker显示逻辑错误:重复创建
viewPicker实例而非复用已有实例,引发视图叠加和布局异常。
修复方案
1. 修改属性定义
将全局datePicker改为可选类型,避免重复使用同一个实例:
var datePicker: UIDatePicker?
2. 重构showDatePicker()方法
使用AutoLayout替代固定Frame,实现动态适配,并复用已有Picker容器:
func showDatePicker(){ // 复用已有的picker容器,避免重复创建 if let existingPicker = viewPicker { existingPicker.isHidden = false return } viewPicker = UIView() viewPicker?.backgroundColor = .white viewPicker?.clipsToBounds = true viewPicker?.translatesAutoresizingMaskIntoConstraints = false // 创建新的日期选择器实例 datePicker = UIDatePicker() guard let picker = datePicker else { return } picker.datePickerMode = .date picker.minimumDate = Calendar.current.date(byAdding: .month, value: -2, to: Date()) picker.maximumDate = Date() picker.backgroundColor = .white if #available(iOS 14.0, *) { picker.preferredDatePickerStyle = .inline } else if #available(iOS 13.4, *) { picker.preferredDatePickerStyle = .wheels } picker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged) picker.translatesAutoresizingMaskIntoConstraints = false // 构建工具栏 let toolbar = UIToolbar() toolbar.sizeToFit() toolbar.translatesAutoresizingMaskIntoConstraints = false let doneButton = UIBarButtonItem(title: "完成", style: .plain, target: self, action: #selector(donedatePicker)) let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let cancelButton = UIBarButtonItem(title: "取消", style: .plain, target: self, action: #selector(cancelDatePicker)) toolbar.setItems([doneButton, spaceButton, cancelButton], animated: false) // 添加子视图并设置约束 viewPicker?.addSubview(toolbar) viewPicker?.addSubview(picker) view.addSubview(viewPicker!) NSLayoutConstraint.activate([ // 容器视图约束:底部对齐父视图,左右铺满,高度自适应 viewPicker!.bottomAnchor.constraint(equalTo: view.bottomAnchor), viewPicker!.leadingAnchor.constraint(equalTo: view.leadingAnchor), viewPicker!.trailingAnchor.constraint(equalTo: view.trailingAnchor), // 工具栏约束:顶部对齐容器,左右铺满,高度固定 toolbar.topAnchor.constraint(equalTo: viewPicker!.topAnchor), toolbar.leadingAnchor.constraint(equalTo: viewPicker!.leadingAnchor), toolbar.trailingAnchor.constraint(equalTo: viewPicker!.trailingAnchor), toolbar.heightAnchor.constraint(equalToConstant: 50), // 日期选择器约束:工具栏下方布局,左右留边,底部对齐容器 picker.topAnchor.constraint(equalTo: toolbar.bottomAnchor, constant: 10), picker.leadingAnchor.constraint(equalTo: viewPicker!.leadingAnchor, constant: 10), picker.trailingAnchor.constraint(equalTo: viewPicker!.trailingAnchor, constant: -10), picker.bottomAnchor.constraint(equalTo: viewPicker!.bottomAnchor, constant: -10) ]) }
3. 简化日期按钮点击逻辑
@objc func onDateClick(_ sender: UIButton) { btnIndex = sender.tag view.endEditing(true) // 切换picker的显示/隐藏状态,避免重复创建 if let picker = viewPicker { picker.isHidden = !picker.isHidden } else { showDatePicker() } }
4. 修正事件绑定错误
将原代码中错误的目标类AddMemberStep1VC改为当前类:
picker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged)
关键修复说明
- 复用
viewPicker实例,避免重复创建视图导致的层级混乱 - 使用AutoLayout实现动态布局,适配
inline样式日期选择器的可变高度 - 每次显示日期选择器时创建新实例,避免同一个Picker被多次添加到视图中
- 简化显示/隐藏逻辑,提升交互流畅度
内容的提问来源于stack exchange,提问作者user20925367
相关产品推荐
相关产品推荐

