Back in Time: Build an App without Storyboard in UIKit
Before SwiftUI existed, apps were built using UIKit. Many associate UIKit with storyboards, but most of the time you just used code to create a UI. By getting rid of the storyboard. In this article, I’ll go into how to create an app in UIKit without a storyboard.
We are creating a VAT calculator app to calculate the gross price.
1. Prepare the app
First we delete the Main.storyboard and move it to the trash, because we don’t need it!
Second, we empty the area that says Main, so delete the connection and leave it empty.
In the Info.plist we delete the connection Storyboard Name (click on the minus (-) sign). So the complete line will be deltetd. See image.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let winScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: winScene)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
In the SceneDelegate.swift file we change the code as shown above. It is important that you set the name in the rootViewController equal to the name of your ViewController file. If you start the app now you should see a black screen.
2. The UI elements
Now let’s go to the ViewController.swift file and add the following UI element, preferably above the viewDidoad() method.
private let taxCalculateContentView: UIView = {
let view = UIView()
view.backgroundColor = .blue
view.layer.cornerRadius = 20
view.clipsToBounds = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
First we add a UIView in which we subordinate the UI elements. As in all elements, it is important that the translatesAutoresizingMaskIntoContstraints = false. Because that allows us to use our own AutoLayout later.
private let titleLabel: UILabel = {
let label = UILabel()
label.text = "Value Added Tax"
label.textAlignment = .center
label.textColor = .systemBlue
label.font = UIFont.boldSystemFont(ofSize: 20)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let amountTextField: UITextField = {
let textField = UITextField()
textField.backgroundColor = .white
textField.placeholder = "Amount / Net Price"
textField.borderStyle = .roundedRect
textField.keyboardType = .decimalPad
textField.textAlignment = .center
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
private let percentageTextField: UITextField = {
let textField = UITextField()
textField.backgroundColor = .white
textField.placeholder = "Tax in Percent"
textField.borderStyle = .roundedRect
textField.keyboardType = .numberPad
textField.textAlignment = .center
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
private let resultLabel: UILabel = {
let label = UILabel()
label.text = "Gross Price"
label.textAlignment = .center
label.textColor = .systemPink
label.font = UIFont.systemFont(ofSize: 20)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
Adds two TextFields and two labels below. You can make adjustments yourself or leave my settings.
let calculateButton: UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = .systemBlue
button.setTitle("Calculate", for: .normal)
button.tintColor = .white
button.layer.cornerRadius = 10
button.clipsToBounds = true
button.addTarget(self, action: #selector(calculateActionButton), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
Finally, we have a button with a link to an action in which we calculate the gross price.
3. SubViews and Auto Layout
override func viewDidLoad() {
super.viewDidLoad()
taxCalculateContentView.addSubview(titleLabel)
taxCalculateContentView.addSubview(amountTextField)
taxCalculateContentView.addSubview(percentageTextField)
taxCalculateContentView.addSubview(resultLabel)
taxCalculateContentView.addSubview(calculateButton)
view.backgroundColor = .systemBlue
view.addSubview(taxCalculateContentView)
setupAutoLayout()
}
It is important here, that the UI elements are linked to our self-created UIView. They are added in the viewDidLoad () method. Our UIView is then added to the main view. We also have a method for the Auto Layout.
func setupAutoLayout() {
taxCalculateContentView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
taxCalculateContentView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -20).isActive = true
taxCalculateContentView.heightAnchor.constraint(equalToConstant: view.frame.height / 3).isActive = true
taxCalculateContentView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
titleLabel.topAnchor.constraint(equalTo: taxCalculateContentView.topAnchor, constant: 10).isActive = true
titleLabel.leftAnchor.constraint(equalTo: taxCalculateContentView.leftAnchor, constant: 40).isActive = true
titleLabel.rightAnchor.constraint(equalTo: taxCalculateContentView.rightAnchor, constant: -40).isActive = true
titleLabel.heightAnchor.constraint(equalToConstant: 40).isActive = true
amountTextField.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10).isActive = true
amountTextField.leftAnchor.constraint(equalTo: taxCalculateContentView.leftAnchor, constant: 40).isActive = true
amountTextField.rightAnchor.constraint(equalTo: taxCalculateContentView.rightAnchor, constant: -40).isActive = true
amountTextField.heightAnchor.constraint(equalToConstant: 40).isActive = true
percentageTextField.topAnchor.constraint(equalTo: amountTextField.bottomAnchor, constant: 20).isActive = true
percentageTextField.leftAnchor.constraint(equalTo: taxCalculateContentView.leftAnchor, constant: 60).isActive = true
percentageTextField.rightAnchor.constraint(equalTo: taxCalculateContentView.rightAnchor, constant: -60).isActive = true
percentageTextField.heightAnchor.constraint(equalToConstant: 40).isActive = true
resultLabel.topAnchor.constraint(equalTo: percentageTextField.bottomAnchor, constant: 20).isActive = true
resultLabel.leftAnchor.constraint(equalTo: taxCalculateContentView.leftAnchor, constant: 60).isActive = true
resultLabel.rightAnchor.constraint(equalTo: taxCalculateContentView.rightAnchor, constant: -60).isActive = true
resultLabel.heightAnchor.constraint(equalToConstant: 40).isActive = true
calculateButton.topAnchor.constraint(equalTo: resultLabel.bottomAnchor, constant: 20).isActive = true
calculateButton.leftAnchor.constraint(equalTo: taxCalculateContentView.leftAnchor, constant: 40).isActive = true
calculateButton.rightAnchor.constraint(equalTo: taxCalculateContentView.rightAnchor, constant: -40).isActive = true
calculateButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
}
First we create the constraints of our taxCalculateContentView and calculate the height so that it is centered.
I will only go into this briefly, as otherwise it would go beyond the length of the article. The other elements are arranged in a way that suits me at first. It is best, to try out the constraints, this is the only way to know what each constraint does.
4. UIButton Action and Summary
@objc func calculateActionButton(sender: UIButton!) {
let amount = amountTextField.text?.replacingOccurrences(of: ",", with: ".")
let percentage = percentageTextField.text
if !amount!.isEmpty && !percentage!.isEmpty {
let result = Double(amount!)! * (1 + (Double(percentage!)! / 100))
resultLabel.text = "Gross Price: \(String(format: "%.2f", result))"
}
}
If we now click the button, the calculateActionButton (…) method is called (see above). Here the values of the text fields are transferred, converted into a double and calculated. If the fields are empty, nothing happens. Finally, the result is transferred to the resultLabel.
This is what the end result should look like. I hope you enjoyed my excursion. UIKit also offers advantages. Despite the time of SwiftUI, you can also work in UIKit without a storyboard and it is advantageous to deal with it. Many tech companies still use UIKit (mostly without a storyboard). So in addition to SwiftUI, you should also know the basics of UIKit, because that can help in the future.
You can download the full project here: