こんばんは、iOSエンジニアの奥江です。
少しばかり苦戦したところを共有したいと思います。
問題
datePickerを5分刻みの時間を設定して時間を取得してもLabelに反映される時間が5分刻みの時間になりませんでした。
原因
iOS14まではroundsToMinuteIntervalが無効なことが原因でした。ドキュメントをもっと読まないとダメですね、、
https://developer.apple.com/documentation/uikit/uidatepicker/3791478-roundstominuteinterval
解決方法
iOS14でも5分(ここは適当な数字を設定できます)刻みで取得できるようにしたいと思います。
今回はTextFieldをタップしたらdatePickerを表示して時間と分を取得するようにします。
viewController
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
let datePicker = UIDatePicker()
override func viewDidLoad() {
super.viewDidLoad()
createToolBar()
prepareSetting()
}
private func createToolBar() {
let toolBar = UIToolbar()
let doneButton = UIBarButtonItem(title: "完了",
style: .done,
target: nil,
action: #selector(doneButtonDidTap))
let cancellButton = UIBarButtonItem(title: "キャンセル",
style: .plain,
target: nil,
action: #selector(cancellButtonDidTap))
let specer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace,
target: nil,
action: nil)
toolBar.setItems([cancellButton, specer, doneButton], animated: false)
toolBar.sizeToFit()
textField.inputAccessoryView = toolBar
}
private func prepareSetting() {
// datePickerを5分刻みにする
datePicker.minuteInterval = 5
// 時間表示にする
datePicker.datePickerMode = .time
// スタイルをドラム式にする
datePicker.preferredDatePickerStyle = .wheels
// textFieldにdatePickerをセット
textField.inputView = datePicker
// textFieldのdelegate先をselfにする
textField.delegate = self
}
@objc
private func doneButtonDidTap() {
// iOS 15.0以上の時はそのまま返す。15.0以下だと四捨五入して返す
let date: Date = {
if #available(iOS 15.0, *) {
return datePicker.date
} else {
return datePicker.date.roundsToMinuteIntervalDate()
}
}()
textField.text = date.dateToString()
view.endEditing(true)
}
@objc
private func cancellButtonDidTap() {
view.endEditing(true)
}
}
extension ViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.endEditing(true)
return true
}
}
extension
extension Date {
// dateをStringに変換する
func dateToString() -> String {
let dateFormat = DateFormatter()
dateFormat.dateFormat = "HH:mm"
return dateFormat.string(from: self)
}
// 時間と分を取得して分を四捨五入し新たなDateを返す
// 5分刻みの場合の計算
func roundsToMinuteIntervalDate() -> Date {
let calender = Calendar(identifier: .gregorian)
let hour = Calendar.appCalender.component(.hour, from: self)
let minute = Calendar.appCalender.component(.minute, from: self)
// minuteが5で割り切れない場合はそのままの分を返す
let roundMinute: Int = {
if minute % 5 == 0 {
return minute
} else {
return (5 - minute % 5) + minute
}
}()
return calender.date(from: DateComponents(hour: hour, minute: roundMinute)) ?? Date()
}
}
extension Calendar {
static var appCalender: Calendar = {
var calender = Calendar(identifier: .gregorian)
calender.timeZone = TimeZone(identifier: "Asia/Tokyo")!
calender.locale = Locale(identifier: "ja_JP")
return calender
}()
}
こんなことあんまりしないと思いますが、参考までにどうぞ