Create UIViews Programmatically In Swift

  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: