Last active
March 14, 2022 05:58
-
-
Save matnogaj/d6ffa9bd44ed52a38440 to your computer and use it in GitHub Desktop.
Custom date picker with "infinite" hours and minutes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import UIKit | |
| @objc protocol CustomDatePickerSourceDelegate:NSObjectProtocol { | |
| func datePickerDidSelectDate(date:NSDate) | |
| } | |
| @objc class CustomDatePickerSource: NSObject { | |
| enum Component:Int { | |
| case Day = 0 | |
| case Hour = 1 | |
| case Minute = 2 | |
| } | |
| private let currentDate = NSDate() | |
| private let dateFormatter = NSDateFormatter() | |
| private let numberFormatter = NSNumberFormatter() | |
| private var days:[NSDate] = [] | |
| private var hours:[Int] = [] | |
| private var minutes:[Int] = [] | |
| @IBOutlet weak var delegate:CustomDatePickerSourceDelegate? | |
| private var selectedDate:(day:NSDate, hour:Int, minute:Int) | |
| override init() { | |
| selectedDate.day = currentDate | |
| selectedDate.hour = 0 | |
| selectedDate.minute = 0 | |
| super.init() | |
| dateFormatter.dateStyle = .MediumStyle | |
| dateFormatter.timeStyle = .NoStyle | |
| numberFormatter.formatWidth = 2 | |
| numberFormatter.paddingPosition = .BeforePrefix | |
| numberFormatter.paddingCharacter = "0" | |
| let currentDateComponents = NSCalendar.currentCalendar().components([NSCalendarUnit.Hour, NSCalendarUnit.Minute], fromDate: currentDate) | |
| days = setupDate(currentDate) | |
| hours = setupHours(currentDateComponents.hour) | |
| minutes = setupMinutes(currentDateComponents.minute, interval: 5) | |
| selectedDate.day = days[0] | |
| selectedDate.hour = hours[0] | |
| selectedDate.minute = minutes[0] | |
| } | |
| private func setupDate(startingDate:NSDate) -> [NSDate] { | |
| var result:[NSDate] = [] | |
| let calendar = NSCalendar.currentCalendar() | |
| let todayComponents = NSDateComponents() | |
| todayComponents.day = calendar.component(.Day, fromDate: startingDate) | |
| todayComponents.month = calendar.component(.Month, fromDate: startingDate) | |
| todayComponents.year = calendar.component(.Year, fromDate: startingDate) | |
| let dayComponent = NSDateComponents() | |
| dayComponent.day = 1 | |
| if let today = calendar.dateFromComponents(todayComponents) { | |
| result.append(today) | |
| var nextDay = today | |
| for _ in 0...365 { | |
| if let date = calendar.dateByAddingComponents(dayComponent, toDate: nextDay, options: NSCalendarOptions(rawValue: 0)) { | |
| result.append(date) | |
| nextDay = date | |
| } | |
| } | |
| } | |
| return result | |
| } | |
| private func setupHours(startingHour:Int) -> [Int] { | |
| var result:[Int] = [] | |
| for i in 0..<24 { | |
| let value = (startingHour + i) % 24 | |
| result.append(value) | |
| } | |
| return result | |
| } | |
| private func setupMinutes(startingMinute:Int, interval:Int = 1) -> [Int] { | |
| var result:[Int] = [] | |
| let count = Int(60.0 / Double(interval)) | |
| for i in 0..<count { | |
| let value = ((Int(ceil(Double(startingMinute) / Double(interval))) + i + 1) * interval) % 60 | |
| result.append(value) | |
| } | |
| return result | |
| } | |
| private func currentSelectedDate() -> NSDate? { | |
| let timeComponents = NSDateComponents() | |
| timeComponents.hour = selectedDate.hour | |
| timeComponents.minute = selectedDate.minute | |
| if let date = NSCalendar.currentCalendar().dateByAddingComponents(timeComponents, toDate: selectedDate.day, options: NSCalendarOptions(rawValue: 0)) { | |
| return date | |
| } | |
| return nil | |
| } | |
| } | |
| extension CustomDatePickerSource : UIPickerViewDataSource { | |
| func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { | |
| return 3 | |
| } | |
| func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { | |
| if let column = Component(rawValue: component) { | |
| switch column { | |
| case .Day: return days.count | |
| case .Hour: return Int(Int16.max)//hours.count | |
| case .Minute: return Int(Int16.max)//minutes.count | |
| } | |
| } | |
| return 10 | |
| } | |
| } | |
| extension CustomDatePickerSource : UIPickerViewDelegate { | |
| func pickerView(pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat { | |
| if let column = Component(rawValue: component) { | |
| switch column { | |
| case .Day: return 150.0 | |
| case .Hour: return 40.0 | |
| case .Minute: return 40.0 | |
| } | |
| } | |
| return 100.0 | |
| } | |
| func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { | |
| return 50.0 | |
| } | |
| func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { | |
| if let column = Component(rawValue: component) { | |
| switch column { | |
| case .Day: | |
| return dateFormatter.stringFromDate(days[row]) | |
| case .Hour: | |
| return "\(numberFormatter.stringFromNumber(hours[row % hours.count])!)" | |
| case .Minute: | |
| return "\(numberFormatter.stringFromNumber(minutes[row % minutes.count])!)" | |
| } | |
| } | |
| return "" | |
| } | |
| func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { | |
| if let column = Component(rawValue: component) { | |
| switch column { | |
| case .Day: selectedDate.day = days[row] | |
| case .Hour: selectedDate.hour = hours[row % hours.count] | |
| case .Minute: selectedDate.minute = minutes[row % minutes.count] | |
| } | |
| } | |
| if let date = currentSelectedDate() { | |
| delegate?.datePickerDidSelectDate(date) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment