How to Easily Write Auto Layout Constraints Programmatically with SnapKit

Is defining Auto Layout constraints programmatically seems to be hard to do ? Do you prefer not to make constraints in code ’cause you know you may blew it up with a bunch of unsatisfiable constraints ? Well, you are in the right place, my purpose here is to get you introduced to a great language that will make your life with Auto Layout constraints simpler and easier than before, like it is supposed to be.

SnapKit…and You’re Done!

SnapKit is an Auto Layout DSL (Domain-specific language) for iOS and OS X programming. It offers a great level of constraints abstraction which means that you choose the right constraints to lay out the screen, and SnapKit will take care of the rest in the process. You will experiment with this right away.

In order to demonstrate the power of SnapKit, we will work together in laying out the following interface using SnapKit constraints system.

screen layout using interface builder constraints

screen layout using interface builder constraints

I have prepared a starter project with all the constraints set up in interface builder for now. Start by downloading it here.

Open up the project in Xcode and run it on your device, or on the simulator. Try to run the project using any screen size (3.5 inch or later, iPad or iPhone) and orientation (portrait and landscape) to make sure the UI elements are positioned correctly on the screen whatever the screen dimension and orientation is.

Have a look at Main.storyboard. The Document Outline view shows three main views with their relevant constraints.

Document Outline view

The screen is basically divided into 3 subviews. One on the top, and two are juxtaposed below the top view.

Dividing the screen into subviews will make the layout job easier since each element (the logo and the buttons) will be positioned relatively to its superview, the relative positioning is cleaner and more efficient.

Below is the screen sections you will set up in a bit.

The screen is divided into three subviews

As you can see, each element (the logo and both buttons) is centered vertically and horizontally inside its superview.

As a first step, you gonna setup the layout for all the superviews coloured above, then you will position the buttons and the logo inside their parent views respectively.

From the Document Outline view in Main.storyboard file, expand the View elements by selecting the left triangle. Hold the command key (cmd) and select all the views and constraints you have inside the View.

Once they are selected, remove them by pressing the delete key in your keyboard.

Select all the elements inside the View in the Document Outline

Now if you run the app again, you will notice the screen is empty. As I said, you will rebuild the whole screen with all the auto layout constraints using SnapKit system, instead of the default layout which was set up in interface builder. At the end, the screen will be backed up as before πŸ™‚

Integrating SnapKit into Xcode:

SnapKit can be embedded to Xcode, in one of three ways. Either as a submodule or via one of the dependencies managers (cocoapods or carthage). In this tutorial, you will set up SnapKit using cocoapods.

If you don’t have cocoapods installed on your machine, head over here to make sure it’s set up correctly, OR follow the steps below:

1/ Type the following command in the Terminal to install cocoapods on your machine (if it’s not already):

sudo gem install cocoapods

2/ cd to the project directory (where SnapKit Tutorial.xcodeproj file is placed), then run the following command to set up the CocoaPods master repo :

pod setup

You should see a message like Setup completed appears in the Terminal to make sure everything is going as expected.

3/ Next, run the following command to make a new Podfile for your Xcode project:

touch Podfile

4/ Edit the Podfile, this can be done directly from within the Terminal by typing the following command:

open -e Podfile

5/ Fill in the Podfile with the following dependency installation:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

pod 'SnapKit', '~> 0.12.0'

Save and close the Podfile.

3/ Run the following command to install the dependencies for your project:

pod install

You should see a message like the following showing up in the Terminal:

installing snapkit using cocoapods

Cool, SnapKit is now integrated correctly with your Xcode project, now you should close the project and open the new workspace file generated automatically by cocoapods.

You should always use the xcworkspace file instead of the xcodeproj file

Double click on the SnapKit Tutorial.xcworkspace file to open in Xcode. You may notice a new target called Pod is now added to the project, and SnapKit framework is now a new Pod inside the Pods folder.

All dependencies are added to the Pods folder

Nice work, SnapKit is now ready to be used. Now it’s time to tweak some SnapKit constraints and get your screen layout up and running as it was before.

The goal is to make a view in the top that fills in 50% of the screen, and two other views to fill in each one 25% of the screen space, both will be placed below the top view. So how you can do that in SnapKit ?

Select ViewController.swift file from the Project navigator to open it in the editor.

Before you start coding, you need to import the SnapKit framework in your code, place the following import statement before the class name:

import SnapKit

Locate the viewDidLoad function and add the following code after the super.viewDidLoad() call:

   //1
   let topView = UIView()
   topView.backgroundColor = UIColor.blueColor()
        
   let bottomLeftView = UIView()
   bottomLeftView.backgroundColor = UIColor.yellowColor()
        
   let bottomRightView = UIView()
   bottomRightView.backgroundColor = UIColor.grayColor()
        
   self.view.addSubview(topView)
   self.view.addSubview(bottomLeftView)
   self.view.addSubview(bottomRightView)
   
   //2     
   topView.snp_makeConstraints { (make) -> Void in
       make.top.left.right.equalTo(0)
       make.height.equalTo(self.view.snp_height).multipliedBy(0.5)
   }
   //3     
   bottomLeftView.snp_makeConstraints { (make) -> Void in
       make.left.bottom.equalTo(0)
       make.height.equalTo(self.view.snp_height).multipliedBy(0.5)
       make.width.equalTo(self.view.snp_width).multipliedBy(0.5)
   }
   //4     
   bottomRightView.snp_makeConstraints { (make) -> Void in
       make.right.bottom.equalTo(0)
       make.width.equalTo(self.view.snp_width).multipliedBy(0.5)
       make.height.equalTo(self.view.snp_height).multipliedBy(0.5)
   }

Let’s explain the code above:

//1 : Here you just made three views with some background color to better visualise their frames when running the project, and you add them as subviews to the root view.

//2 : Starting by the top view, you basically asked SnapKit to set its top, left and right spacing to 0 so that the view will always stick to the top of the screen and never cross the left and right boundaries of the screen.

Also, you set up an equality relation between the height of the top view and the height of the root view (the screen). This relation imposes that the height of the top view will always be the half of the root view height. This way, you will ensure the top view is always filling exactly 50% of the screen, regardless of the screen size and orientation.

//3 : For the bottomLeftView, you set its left and bottom spacing constraints to 0, and its height and width to be calculated as the half of the root view. This way, the bottomLeftView will always fill the 25% of the screen located in the bottom left.

//4 : This is basically the same logic as for the previous bottomLeftView, except that you set the constraints to align it on the bottom right 25% of the screen.

So far so good, run the project and change the orientation of your device or simulator to make sure all views are filling the right space of the screen.

Positioning the logo and the buttons:

Now it’s time to put each element inside its container. The logo will be centered in the top view, while the buttons will be placed in the left and right views at the bottom.

Start by adding the logo image, place the following code inside the viewDidLoad function, right after the previous code:

 let logo = UIImageView(image: UIImage(named: "logo"))
 topView.addSubview(logo)
    logo.snp_makeConstraints { (make) -> Void in
       make.center.equalTo(topView.center)
       make.width.equalTo(100)
       make.height.equalTo(110)
 }

This is pretty straightforward. As you did for the previous views, the logo is basically another view that is embedded inside a superview. This time, the superview is the topView. Besides setting the logo width and height, you just set the logo center to be the same as the topView center, this way, you guarantee that the logo is always centered vertically and horizontally with just a single line of code πŸ™‚

Let’s finish up by laying out the remaining buttons. Copy the following code and place it before the closing bracket of viewDidLoad function:

        var tutorialsBtn = UIButton()
        tutorialsBtn.setTitle("Tutorials", forState: UIControlState.Normal)
        tutorialsBtn.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
        tutorialsBtn.backgroundColor = UIColor.redColor()
        bottomLeftView.addSubview(tutorialsBtn)
        
        var quizBtn = UIButton()
        quizBtn.setTitle("Quiz", forState: UIControlState.Normal)
        quizBtn.setTitleColor(UIColor.whiteColor(), forState: UIControlState.Normal)
        quizBtn.backgroundColor = UIColor.redColor()
        bottomRightView.addSubview(quizBtn)

        tutorialsBtn.snp_makeConstraints { (make) -> Void in
            make.center.equalTo(bottomLeftView.center)
            make.width.equalTo(100)
            make.height.equalTo(25)
        }
        
        quizBtn.snp_makeConstraints { (make) -> Void in
            make.center.equalTo(bottomRightView.center)
            make.width.equalTo(100)
            make.height.equalTo(25)
        }

The code above will set up two buttons (tutorialsBtn and quizBtn) and will add them to the bottomLeftView and bottomRightView respectively. Then, it will set some constraints to make them centered vertically and horizontally inside their containers.

That’s it, run the project and enjoy the screen layout. Feel free to test the project with different screen sizes and orientations to make sure you did well your job. Also, don’t forget to remove the color backgrounds from the code, that was only to distinguish the elements’ frames in the screen, you surely don’t like those colours anyway πŸ™‚

As usual, the final project is ready for you, download it here.

SnapKit is saving me a lot of time and effort when I need to define constraints programmatically, if I have to write the same constraints I wrote in this tutorial, but using Apple syntax, the code would become way longer and way less readable.

I am sure SnapKit will save your time as well, so don’t hesitate to work with it in your projects.

In this tutorial, I have showed you some of the great tools of SnapKit, but its arsenal has plenty of other sweet tools you will enjoy!

What do you think about SnapKit ? leave a comment below, I’d love to hear your thoughts πŸ™‚

Malek
iOS developer with over than 11 years of extensive experience working on several projects with different sized startups and corporates.

7 Comments

  1. Very nice post. That helped a lot in understanding SnapKit.

    One small issue: when creating the subviews, you should use the UIView designated initialiser, that is, initWithFrame. That way, the code looks more correct.

Comments are closed.