在 UIDatePicker 中的小时和分钟之间添加冒号 (:) 并禁用默认值 AM/PM

Add Colon (:) between Hour and Minute & Disable default AM/PM in UIDatePicker

我正在尝试为 12-Hour 格式禁用 UIDatePicker 中的默认 AM/PM,并尝试在 Hour 和 Hour 之间添加冒号 (:)分钟。但是没有做到。

我在日期选择器中设置了以下代码以在 UIDatePicker 中设置时间。

self.datePicker.datePickerMode = .time

以上代码显示时间为 12 小时制,AM/PM。

见下图:

谁能帮我解决这个问题?

我相信 UIDatePicker 使用本地时间配置,所以我不建议您更改它。尽管如此,更改 dateTimePicker.locale 应该就足够了。

UIDatePicker 应按原样使用,无需自定义。你不应该弄乱它的观点,所以你可能会倒霉。如果您想要 UIDatePicker 不提供的行为,那么您可能需要使用 UIPickerView 创建您自己的控件。

引用文档:

Appearance

The appearance of UIDatePicker is not customizable.

为此,您将创建一个包含 2 个组件(小时和分钟)的选择器视图,并设置一个数据源,其中一个组件附加了一个冒号。请注意,组件也会滚动冒号,这可能不是您想要的。

您始终可以创建一个完全自定义的控件,但要让它完全按照您的要求进行操作需要大量工作,并且可能需要使用 CALayersCAAnimation,这两者相当先进

我认为最好的解决方案是简单地使用普通 UIPickerView。这样你几乎可以控制一切。作为演示,我创建了这个全代码示例,它几乎可以满足您的要求:

class ViewController: UIViewController {

    private let pickerView: UIPickerView = UIPickerView(frame: CGRect(x: 0.0, y: 300.0, width: 100.0, height: 300.0))

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(pickerView)
        pickerView.dataSource = self
        pickerView.delegate = self
        pickerView.reloadAllComponents()
        pickerView.selectRow(50000, inComponent: 0, animated: false)
        pickerView.selectRow(50000, inComponent: 1, animated: false)

        view.addSubview({
            let label = UILabel(frame: .zero)
            label.text = ":"
            label.sizeToFit()
            label.center = pickerView.center
            label.isUserInteractionEnabled = false
            return label
        }())
    }

}

extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate {

    private func hourValueAtIndex(index: Int) -> Int {
        return index%12
    }
    private func minuteValueAtIndex(index: Int) -> Int {
        return index%60
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return 100000
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch component {
        case 0: return String(hourValueAtIndex(index: row))
        case 1: return String(minuteValueAtIndex(index: row))
        default: return ""
        }
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        let calendarToUse = Calendar.autoupdatingCurrent
        var components = calendarToUse.dateComponents([.year, .month, .day], from: Date())
        components.hour = hourValueAtIndex(index: pickerView.selectedRow(inComponent: 0))
        components.minute = minuteValueAtIndex(index: pickerView.selectedRow(inComponent: 1))
        let selectedDate = calendarToUse.date(from: components)

        print("Selected new time (in UTC): \(selectedDate!)")

        let formatter = DateFormatter()
        formatter.calendar = calendarToUse
        formatter.dateStyle = .short
        formatter.timeStyle = .short
        print("Selected new time (local): \(formatter.string(from: selectedDate!))")
    }

}

我会把这一切都放在故事板中,甚至放在 xib 中,以便在需要时可以重复使用。冒号的定位和样式可能需要一些工作,但这取决于您想要的设计。我只是为组件使用了 100k 的值来模拟无限滚动。至少应该为此定义一些常量。

通知hourValueAtIndexminuteValueAtIndex;这些可以被操纵以使用几乎任何你需要的东西。要获得 0-23 小时,您只需使用 index%24。但是,要使用它 1-24 需要做更多的工作:您会 return index%24 + 1 但是在构建日期时,您需要将 24 的值作为异常处理。您将使用 0 并添加额外的一天。但是您不能直接向组件添加额外的一天,因为您可能会在 7 月 32 日等情况下溢出。您确实需要在末尾添加一天:

selectedDate = calendarToUse.date(byAdding: DateComponents(day: 1), to: selectedDate)