Create Uiviews Programmatically in Swift

Monday Oct 21, 2019 by Dave Glassanos

  1. A good place to start is to read through Apple’s documentation for the UIView class.

  2. Install PureLayout. PureLayout provides a developer friendly API for defining layout constraints for Auto Layout. Writing Auto Layout code from scratch isn’t easy, so PureLayout handles most of the complexity for us.

    Use cocoapods to add PureLayout to your project.

    platform :ios, "10.0"
    use_frameworks!
       
    pod "PureLayout"
    

    Now install the dependency.

    pod install
    

    The first time you run this it will create a new project file that ends in .xcworkspace. From now on you should open this project in Xcode when working on the project.

  3. Build a custom class. Create a new file called ProfileView.swift and add the following code:

    import UIKit
       
    class ProfileView: UIView {
       
    }
    

    Next, add our initializers.

    import UIKit
       
    class ProfileView: UIView {
           
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
           
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
           
    }
    

    We also want to override the updateConstraints method on the UIView so that PureLayout can set up our auto layout constraints. Since updateConstraints can be called multiple times once it’s initialized, add a boolean variable called shouldSetupConstraints to our class and toggle it off once it’s called once. Note that we also import PureLayout in this step.

    import UIKit
    import PureLayout
       
    class ProfileView: UIView {
        var shouldSetupConstraints = true
                   
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
           
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
           
        override func updateConstraints() {
            if (shouldSetupConstraints) {
                // AutoLayout constraints
                shouldSetupConstraints = false
            }
            super.updateConstraints()
        }
    }
    
  4. Now comes the fun part. We want our profile view to contain a mainPhoto, bannerPhoto, and a callToAction components so we will create them now. First declare the three objects in our ProfileView class.

    import UIKit
    import PureLayout
           
    class ProfileView: UIView {
        var shouldSetupConstraints = true
           
        var bannerPhotoView: UIImageView!
        var mainPhotoView: UIImageView!
        var callToActionButton: UIButton!
                   
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
           
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
           
        override func updateConstraints() {
            if (shouldSetupConstraints) {
                // AutoLayout constraints
                shouldSetupConstraints = false
            }
            super.updateConstraints()
        }
    }    
    
  5. Now we’re ready to create our components and add them to our ProfileView view. First set the background color of ProfileView to white. Then configure the bannerPhotoView, mainPhotoView, and callToActionButton and add them to the view.

    Notice how we’re initializing each component’s frame to zero. That’s because we’re going to allow Auto Layout to take care of that later.

    import UIKit
    import PureLayout
       
    class ProfileView: UIView {
        var shouldSetupConstraints = true
           
        var bannerPhotoView: UIImageView!
        var mainPhotoView: UIImageView!
        var callToActionButton: UIButton!
           
        let screenSize = UIScreen.main.bounds
        let edgesInset: CGFloat = 10.0
        let centerOffset: CGFloat = 62.0
           
        override init(frame: CGRect) {
            super.init(frame: frame)
               
            self.backgroundColor = UIColor.white
               
            bannerPhotoView = UIImageView(frame: CGRect.zero)
            bannerPhotoView.backgroundColor = UIColor.gray
            bannerPhotoView.autoSetDimension(.height, toSize: screenSize.width / 3)
               
            mainPhotoView = UIImageView(frame: CGRect.zero)
            mainPhotoView.backgroundColor = UIColor.gray
            mainPhotoView.layer.borderColor = UIColor.white.cgColor
            mainPhotoView.layer.borderWidth = 1.0
            mainPhotoView.layer.cornerRadius = 5.0
            mainPhotoView.autoSetDimension(.width, toSize: 124.0)
            mainPhotoView.autoSetDimension(.height, toSize: 124.0)
               
            callToActionButton = UIButton(frame: CGRect(x: edgesInset, y: screenSize.height - 100, width: screenSize.width - (edgesInset * 2), height: 50))
            callToActionButton.layer.cornerRadius = 5.0
            callToActionButton.backgroundColor = UIColor(red: 10/255, green: 178/255, blue: 89/255, alpha: 1.0) /* #0ab259 */
            callToActionButton.setTitle("Book", for: .normal)
            callToActionButton.addTarget(self, action: #selector(callToActionButtonAction), for: .touchUpInside)
               
            self.addSubview(bannerPhotoView)
            self.addSubview(mainPhotoView)
            self.addSubview(callToActionButton)
        }
           
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
           
        override func updateConstraints() {
            if (shouldSetupConstraints) { 
                // AutoLayout constraints                           
                shouldSetupConstraints = false
            }
            super.updateConstraints()
        }
    }
    
  6. Now we’re ready to start pinning our components and letting Auto Layout take care of the rest.

    import UIKit
    import PureLayout
       
    class ProfileView: UIView {
        var shouldSetupConstraints = true
           
        var bannerPhotoView: UIImageView!
        var mainPhotoView: UIImageView!
        var callToActionButton: UIButton!
           
        let screenSize = UIScreen.main.bounds
        let edgesInset: CGFloat = 10.0
        let centerOffset: CGFloat = 62.0
           
        override init(frame: CGRect) {
            super.init(frame: frame)
               
            self.backgroundColor = UIColor.white
               
            bannerPhotoView = UIImageView(frame: CGRect.zero)
            bannerPhotoView.backgroundColor = UIColor.gray
            bannerPhotoView.autoSetDimension(.height, toSize: screenSize.width / 3)
               
            mainPhotoView = UIImageView(frame: CGRect.zero)
            mainPhotoView.backgroundColor = UIColor.gray
            mainPhotoView.layer.borderColor = UIColor.white.cgColor
            mainPhotoView.layer.borderWidth = 1.0
            mainPhotoView.layer.cornerRadius = 5.0
            mainPhotoView.autoSetDimension(.width, toSize: 124.0)
            mainPhotoView.autoSetDimension(.height, toSize: 124.0)
               
            callToActionButton = UIButton(frame: CGRect(x: edgesInset, y: screenSize.height - 100, width: screenSize.width - (edgesInset * 2), height: 50))
            callToActionButton.layer.cornerRadius = 5.0
            callToActionButton.backgroundColor = UIColor(red: 10/255, green: 178/255, blue: 89/255, alpha: 1.0) /* #0ab259 */
            callToActionButton.setTitle("Book", for: .normal)
            callToActionButton.addTarget(self, action: #selector(callToActionButtonAction), for: .touchUpInside)
               
            self.addSubview(bannerPhotoView)
            self.addSubview(mainPhotoView)
            self.addSubview(callToActionButton)
        }
           
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
           
        override func updateConstraints() {
            if (shouldSetupConstraints) {
                   
                bannerPhotoView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .bottom)
                   
                mainPhotoView.autoPinEdge(toSuperviewEdge: .left, withInset: edgesInset)
                mainPhotoView.autoPinEdge(.bottom, to: .bottom, of: bannerPhotoView, withOffset: centerOffset)
                   
                callToActionButton.autoPinEdge(toSuperviewEdge: .bottom, withInset: edgesInset)
                callToActionButton.autoPinEdge(toSuperviewEdge: .left, withInset: edgesInset)
                callToActionButton.autoPinEdge(toSuperviewEdge: .right, withInset: edgesInset)
                   
                shouldSetupConstraints = false
            }
            super.updateConstraints()
        }
           
        @objc func callToActionButtonAction(sender: UIButton!) {
            print("Button tapped")
        }
    } 
    
  7. Almost done! Last thing we need to do is initialize our ProfileView object when our ViewController calls viewDidLoad. Go to ViewController.swift and add the following to viewDidLoad. Make sure to declare our ProfileView object up top too.

    import UIKit
       
    class ViewController: UIViewController {
      var profile: ProfileView!
         
      override func viewDidLoad() {
        super.viewDidLoad()
       
        profile = ProfileView(frame: CGRect.zero)
        self.view.addSubview(profile)
           
        // AutoLayout
        profile.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets.zero)
      }
       
      override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
      }
    }
    

If all went according to plan you should be able to run your app and see the following components: