Programatically designing a UI View in Swift

This is a basic tutorial for creating a View in Swift programatically without storyboards. This allows for more control and makes it easier to work collaboratively on projects. For now this post is just notes but I’ll update it as I understand it more.

Setting up the view

  • Create a new Single View Application
  • Delete Main.storyboard (making sure you move the file to trash and not just the reference).
  • Delete ViewController.swift
  • Select info.plist
  • Select the row with the text “Main storyboard file base name” and delete it.
  • open AppDelegate.swift – This is your apps main way of communicating with the operating system.
  • If you click run at this point it should run with a blank screen.
  • click CMD+N to create a new file.
  • Click Cocoa Touch Class
  • Set the subclass to UIViewController and give it an appropriate name such as “MainViewController”.
  • Xcode will create the new file with some boilerplate code.
  • Select AppDelegate.swift
  • Look for the “application: UIApplication, didFinishLaunchingWithOptions launchOptions:” method
  • add the following code to the method
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  
   // Initialize the window
   window = UIWindow.init(frame: UIScreen.main.bounds)
        
   // Set Background Color of window
   window?.backgroundColor = UIColor.white
  
   // Allocate memory for an instance of the 'MainViewController' class
   let mainViewController = MainViewController()
  
   // Set the root view controller of the app's window
   window!.rootViewController = mainViewController
  
   // Make the window visible
   window!.makeKeyAndVisible()
  
   return true
}  
  • Line 4 instantiates an object of the UIWindow class set to the bounds of the iPhone’s screen.
  • Line 7 instantiates an object of our MainViewController class called “mainViewController.”
  • Line 10 sets “viewController” as the window’s root view controller.
  • Finally, line 13 makes the window visible.

Adding Elements

Creating a textfield

  • Open MainViewController.swift
  • Delete lines 10 through 26 as they aren’t needed.
  • We will lazily instantiate an apple-provided class called UITextField – This means the object is only created when it is required
  • Add the following code below the viewDidLoad method:
lazy var textField: UITextField! = {
    let view = UITextField()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.borderStyle = .RoundedRect
    view.textAlignment = .Center
    
    return view
}()
  • translatesAutoresizingMaskIntoConstraints is set to false so we can set our own constraints.
  • Within viewDidLoad add the following code:
view.addSubview(textField)
  • We also need to introduce our AutoLayout code, so add the following code within videoDidLoad
view.setNeedsUpdateConstraints()
  • And add this code to your MainViewController class
override func updateViewConstraints() {
    super.updateViewConstraints()
}
  • updateViewConstraints is called when the view controller’s view needs to update its constraints.
  • Under updateViewConstraints add a new method called textFieldConstraints with the following code

func textFieldConstraints() {
    // Center Text Field Relative to Page View
    NSLayoutConstraint(
      item: textField,
      attribute: .CenterX,
      relatedBy: .Equal,
      toItem: view,
      attribute: .CenterX,
      multiplier: 1.0,
      constant: 0.0)
      .active = true
    
    // Set Text Field Width to be 80% of the Width of the Page View  
    NSLayoutConstraint(
      item: textField,
      attribute: .Width,
      relatedBy: .Equal,
      toItem: view,
      attribute: .Width,
      multiplier: 0.8,
      constant: 0.0)
      .active = true
    
    // Set Text Field Y Position 10% Down From the Top of the Page View    
    NSLayoutConstraint(
      item: textField,
      attribute: .Top,
      relatedBy: .Equal,
      toItem: view,
      attribute: .Bottom,
      multiplier: 0.1,
      constant: 0.0)
      .active = true
}
  • Then add the following line to updateViewConstraints above the super.updateViewConstraints method
override func updateViewConstraints() {
    textFieldConstraints()
    super.updateViewConstraints()
}
  • The MainViewController class should look like this
import UIKit

class MainViewController: UIViewController, UITextFieldDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(textField)
        view.setNeedsUpdateConstraints()
    }
    
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        
        // Dismisses the Keyboard by making the text field resign
        // first responder
        textField.resignFirstResponder()
        
        // returns false. Instead of adding a line break, the text
        // field resigns
        return false
    }
    
    override func updateViewConstraints() {
        textFieldConstraints()
        super.updateViewConstraints()
    }
    
    func textFieldConstraints() {
        NSLayoutConstraint(
            item: textField,
            attribute: .CenterX,
            relatedBy: .Equal,
            toItem: view,
            attribute: .CenterX,
            multiplier: 1.0,
            constant: 0.0)
            .active = true
        
        NSLayoutConstraint(
            item: textField,
            attribute: .Width,
            relatedBy: .Equal,
            toItem: view,
            attribute: .Width,
            multiplier: 0.8,
            constant: 0.0)
            .active = true

        
        NSLayoutConstraint(
            item: textField,
            attribute: .Top,
            relatedBy: .Equal,
            toItem: view,
            attribute: .Bottom,
            multiplier: 0.1,
            constant: 0.0)
            .active = true
    }

    lazy var textField: UITextField! = {
        let view = UITextField()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.borderStyle = .RoundedRect
        return view
    }()

}
  • To make the keyboard disappear programmatically add the following code below your viewDidLoad method
func textFieldShouldReturn(textField: UITextField) -> Bool {   
   // Dismisses the Keyboard by making the text field resign
   // first responder
   textField.resignFirstResponder()
   
   // returns false. Instead of adding a line break, the text 
   // field resigns
   return false
}
  • Go back to the viewDidLoad method and below super.viewDidLoad() line add:
textField.delegate = self
  • Then inside MainViewController.swift, change class MainViewController: UIViewController { to the following line:
class MainViewController: UIViewController, UITextFieldDelegate {
  • Your MainViewController will now look like this:
import UIKit

class MainViewController: UIViewController, UITextFieldDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(textField)
        view.setNeedsUpdateConstraints()
    }
    
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        
        // Dismisses the Keyboard by making the text field resign
        // first responder
        textField.resignFirstResponder()
        
        // returns false. Instead of adding a line break, the text
        // field resigns
        return false
    }
    
    override func updateViewConstraints() {
        textFieldConstraints()
        super.updateViewConstraints()
    }
    
    func textFieldConstraints() {
        NSLayoutConstraint(
            item: textField,
            attribute: .CenterX,
            relatedBy: .Equal,
            toItem: view,
            attribute: .CenterX,
            multiplier: 1.0,
            constant: 0.0)
            .active = true
        
        NSLayoutConstraint(
            item: textField,
            attribute: .Width,
            relatedBy: .Equal,
            toItem: view,
            attribute: .Width,
            multiplier: 0.8,
            constant: 0.0)
            .active = true

        
        NSLayoutConstraint(
            item: textField,
            attribute: .Top,
            relatedBy: .Equal,
            toItem: view,
            attribute: .Bottom,
            multiplier: 0.1,
            constant: 0.0)
            .active = true
    }

    lazy var textField: UITextField! = {
        let view = UITextField()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.borderStyle = .RoundedRect
        return view
    }()

}
  • When you run the app you can tap on the text box and the keyboard will appear. Pressing return should now dismiss the keyboard.

The Button

Let’s repeat this to add a button to our view.

  • Inside viewDidLoad, below view.addSubview(textField) add the following line
view.addSubview(button)
  • Then lazily instantiate the button with the following code
lazy var button: UIButton! = {
    let view = UIButton()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.addTarget(self, action: "buttonPressed", forControlEvents: .TouchDown)
    view.setTitle("Press Me!", forState: .Normal)
    view.backgroundColor = UIColor.blueColor()
    return view
}()
  • The action performed after the button is pressed is identical to what would happen if you called buttonPressed()
  • “UIControlEventTouchDown” is the trigger event for a tap
  • Add the following code within a buttonConstraints method, below the textFieldConstraints method we added earlier.
func buttonConstraints() {
  // Center button in Page View
  NSLayoutConstraint(
    item: button,
    attribute: .CenterX,
    relatedBy: .Equal,
    toItem: view,
    attribute: .CenterX,
    multiplier: 1.0,
    constant: 0.0)
    .active = true
  
  // Set Width to be 30% of the Page View Width
  NSLayoutConstraint(
    item: button,
    attribute: .Width,
    relatedBy: .Equal,
    toItem: view,
    attribute: .Width,
    multiplier: 0.3,
    constant: 0.0)
    .active = true
  
  // Set Y Position Relative to Bottom of Page View
  NSLayoutConstraint(
    item: button,
    attribute: .Bottom,
    relatedBy: .Equal,
    toItem: view,
    attribute: .Bottom,
    multiplier: 0.9,
    constant: 0.0)
    .active = true
}
  • Within the updateViewConstraints method, add the following code to ensure our view is updated, again making sure you add it before the super.updateViewConstraints.
buttonConstraints()
  • Inside viewDidLoad, below view.addSubview(button) add the following line:
view.addSubview(button)
  • To lazily instantiate the label
lazy var label: UILabel! = {
    let view = UILabel()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.text = “Hello World!”
    view.textAlignment = .Center
    
    return view
}()
  • add a labelConstraints method below the textfieldConstraints method
func labelConstraints() {
  // Center button in Page View
  NSLayoutConstraint(
    item: label,
    attribute: .CenterX,
    relatedBy: .Equal,
    toItem: view,
    attribute: .CenterX,
    multiplier: 1.0,
    constant: 0.0)
    .active = true
  
  // Set Width to be 80% of the Page View Width
  NSLayoutConstraint(
    item: label,
    attribute: .Width,
    relatedBy: .Equal,
    toItem: view,
    attribute: .Width,
    multiplier: 0.8,
    constant: 0.0)
    .active = true
  
  // Set Y Position Relative to Bottom of Page View
  NSLayoutConstraint(
    item: label,
    attribute: .CenterY,
    relatedBy: .Equal,
    toItem: view,
    attribute: .CenterY,
    multiplier: 1.0,
    constant: 0.0)
    .active = true
}
  • The inside the updateViewConsteaints method, add the following code
labelConstraints()
  • Under viewDidLoad and before textFieldShouldReturn we’ll create a new method called buttonPressed()
func buttonPressed() {
    // Print Hello followed by the user inputed string
    // The exclamation point is added to unwrap the optional
    label.text = "Hello, \(textField.text!)"
}

That’s it for now.

Jamie De Vivo

(15 Posts)

I'm a digital producer and fourth year student at The Media School at Bournemouth University. Summarising myself is a difficult task, so I'll just leave it to the blog. But my posts will focus on everything from web and app development to behavioural science. Specifically you'll also find my views and advice on cameras, editing, business, culture, mentality, my adventures and my DIY projects. Enjoy.
View all posts

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.