Back in Time: Build an App without Storyboard in UIKit

David Koenig
5 min readSep 24, 2020


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()

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() {


view.backgroundColor = .systemBlue


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: