不使用UITextField实现带工具栏的UIDatePicker,自定义视图不显示怎么办
问题原因
核心错误:子视图坐标系使用错误
所有添加到父视图上的子视图,frame的坐标是相对于父视图的内部坐标系,不是相对于全局屏幕坐标系。
你创建的容器pickerView本身的frame是CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: 屏幕宽, height: 300),它的内部坐标系的顶部是y=0,底部是y=300。但你给内部的toolbar和timePicker设置的y坐标都是基于全局屏幕高度计算,数值远大于300,导致两个子视图都跑到了容器视图的可见区域之外,所以整体看不到。
修正方案
1. 修正子控件frame计算逻辑
static func createTimePickerAndToolbar(displayDate: Date) -> UIView { let screenWidth = UIScreen.main.bounds.width // 容器视图frame不变,基于屏幕坐标放在底部 let pickerView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: screenWidth, height: 300)) // 可选:给容器加背景色避免透明异常 pickerView.backgroundColor = .white let timePicker = createTimePicker(displayDate: displayDate, containerWidth: screenWidth) pickerView.addSubview(timePicker) let toolbar = createUIToolBar(containerWidth: screenWidth) pickerView.addSubview(toolbar) return pickerView } static func createTimePicker(displayDate: Date, containerWidth: CGFloat) -> UIDatePicker { let timePicker:UIDatePicker = UIDatePicker() timePicker.datePickerMode = .time timePicker.date = displayDate timePicker.minuteInterval = 15 if #available(iOS 13.4, *) { timePicker.preferredDatePickerStyle = .wheels } // 相对于父容器的坐标:toolbar高100,所以timePicker从y=100开始,高200 timePicker.frame = CGRect(x: 0, y: 100, width: containerWidth, height: 200) timePicker.backgroundColor = .white timePicker.addTarget(self, action: #selector(timeChanged(_:)), for: .valueChanged) return timePicker } private static func createUIToolBar(containerWidth: CGFloat) -> UIToolbar { let pickerToolbar = UIToolbar() // 相对于父容器的坐标:放在顶部,y=0,高100 pickerToolbar.frame = CGRect(x: 0, y: 0, width: containerWidth, height: 100) pickerToolbar.autoresizingMask = [.flexibleWidth, .flexibleHeight] pickerToolbar.barStyle = .default pickerToolbar.barTintColor = .black pickerToolbar.isTranslucent = false let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelBtnClicked(_:))) cancelButton.tintColor = .white let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneBtnClicked(_:))) doneButton.tintColor = .white pickerToolbar.items = [cancelButton, flexSpace, doneButton] return pickerToolbar }
2. 其他需要修复的潜在问题
- 事件target错误:当前
addTarget用的self是静态方法里的类对象,而你定义的timeChanged、cancelBtnClicked、doneBtnClicked都是实例方法,触发事件时会崩溃。建议改为给工具类加回调闭包属性,或者在创建时把当前控制器作为target传入。 - 适配性优化:如果需要支持横竖屏切换,建议使用AutoLayout代替手动计算frame。
内容的提问来源于stack exchange,提问作者tech_human
相关产品推荐
相关产品推荐

