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

不使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:57:03