Create a custom Start-and-End Time Picker Alert in Swift

Zeba Rahman
fabcoding
Published in
4 min readAug 5, 2020

This tutorial is concise and assumes that you already know how to add constraints, connect outlets, and create delegates.

Leave a comment below if you are a beginner and need assistance with these!

Design

First let us design the alert view.

Drag a ViewController on to your storyboard.

Add a view, add necessary constraints, header labels and the most important part — a UIPickerView. Also add OK and Cancel buttons at the bottom. Here’s how my view looks after design.

Code

Now create a Swift class for this ViewController that we created, named MyTimePickerAlert.swift. We also need to create a Delegate for this, so that we can communicate data back to our main view controller from where we will be presenting this alert.

So here’s the initial code for the file MyTimePickerAlert.swift.

import UIKit

protocol MyTimePickerAlertDelegate: class {
func pickerAlertSelected(t1: String, t2: String)
func pickerAlertCancel()
}

class MyTimePickerAlert: UIViewController {

}

Now, inside the class MyTimePickerAlert, declare outlets for our significant views.

@IBOutlet weak var alertView: UIView!
@IBOutlet weak var cancelButton: UIButton!
@IBOutlet weak var okButton: UIButton!
@IBOutlet weak var pickerView: UIPickerView!

also declare a variable for the delegate

var delegate: MyTimePickerAlertDelegate?

Also, declare arrays to store the start and end times, and a dateformatter instance that will be used for formatting the times.

var startTimes = [String]()
var endTimes = [String]()
let timeFormatter = DateFormatter()

Let us write a function to get a list of all the time values. We shall also pass a parameter to determine the offset for the end times; because we do not want the user to be able to select an END time that is earlier than the START time.

extension MyTimePickerAlert {
func getTimeList(from: Int) -> [String] {
let alllist: [String] = [
"1:00 AM","2:00 AM","3:00 AM","4:00 AM","5:00 AM", "6:00 AM", "7:00 AM", "8:00 AM", "9:00 AM","10:00 AM","11:00 AM", "12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM", "6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM", "10:00 PM", "11:00 PM", "12:00 AM"]
var list: [String] = []
for i in from...alllist.count-1 {
list.append(alllist[i])
}
return list
}
}

Now write the delegate and datasource methods for populating the data of the PickerView.

extension MyTimePickerAlert: UIPickerViewDelegate, UIPickerViewDataSource {

func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
switch component {

case 0:
return startTimes.count
case 1:
return endTimes.count
default:
return 0
}
}

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
var label: UILabel

if let view = view as? UILabel {
label = view
} else {
label = UILabel()
}

label.textColor = .black
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 15)

var text = ""

switch component {
case 0:
text = startTimes[row]
case 1:
text = endTimes[row]
default:
break
}

label.text = text

return label
}

//this is for reloading the END times list, according to the value selected as the START time.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if (component == 0) {

endTimes = getTimeList(from: row)
pickerView.reloadComponent(1)
}

}
}

And, let us initialise the views and set the button actions; and call the delegate function upon user selecting OK.

override func viewDidLoad() {
super.viewDidLoad()

pickerView.delegate = self
pickerView.dataSource = self

timeFormatter.timeStyle = .short
startTimes = getTimeList(from: 0)
endTimes = getTimeList(from: 0)

cancelButton.addTarget(self, action: #selector(cancelMe), for: .touchUpInside)
okButton.addTarget(self, action: #selector(okMe), for: .touchUpInside)

}

@objc func okMe() {
delegate?.pickerAlertSelected(t1: startTimes[pickerView.selectedRow(inComponent: 0)], t2: endTimes[pickerView.selectedRow(inComponent: 1)])
self.dismiss(animated: true, completion: nil)
}

@objc func cancelMe() {
delegate?.pickerAlertCancel()
self.dismiss(animated: true, completion: nil)
}

Go back to your storyboard, find the view controller that we designed for the alert, and change its class to MyTimePickerAlert, and also set storyboard ID as mytimepicker (or anything you like).

Also do not forget to connect all the IBOutlets to their respective views.

Finally, go to the main ViewController class — the screen from where you wish to launch the Picker Alert view and add this code to present the alert view and to handle the actions of OK or Cancel buttons.

extension ViewController: MyTimePickerAlertDelegate {

@objc func showTimePicker() {
let customAlert = self.storyboard?.instantiateViewController(withIdentifier: "mytimepicker") as! MyTimePickerAlert
customAlert.providesPresentationContextTransitionStyle = true
customAlert.definesPresentationContext = true
customAlert.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
customAlert.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
customAlert.delegate = self
self.present(customAlert, animated: true, completion: nil)
}

func pickerAlertCancel() {

}

func pickerAlertSelected(t1: String, t2: String) {
//Do something with the selected times, display it somewhere
print("START time is \(t1) and END time is \(t2)")
}
}

Now just call the function showTimePicker() from any button or textfield click.

showTimePicker()

Originally published at Fabcoding.

--

--