Look mom, no storyboard!
As a self-taught iOS developer who learned most of his skills from watching Youtube tutorials and online courses using storyboards became second nature. For sometime I actually did not even know that there was even an alternative to using storyboards in Xcode. Was I wrong ! As my journey in learning Swift progressed I started seeing a number of projects using programmatic constraints in their projects. So I started researching why one would even want to use an auto-layout DSL. I mean the storyboard works and I did not see any flaws in it (that’s what I thought). Basically this is what I found reasons for why one would abandon the storyboard.
- Collaboration — Storyboards don’t work well with source control. The storyboard is not your friend when wanting to work with your friends.
- Storyboard are slow — Take it from someone who started developing on a 2011 Macbook Air. I got used to seeing that rainbow spinning. 🍭
- Code Master Race — Code will always be superior. It is easier to write, read and debug.
Show Me The Code
This is what we will be building. It is a mock-up of a lock screen for the iPhone X Apple’s latest and greatest. No storyboard and no nibs all with code. There are a number of auto-layout DSL libraries out there. You can find one which you like or feels more natural to your style in this tutorial I’ll be making use of SnapKit.
Project Setup
Delete the Main.storyboard file. Yes delete ! While you’re at it might as well just delete the ViewController.swift too. (Don’t delete the launchscreen.storyboard)
Create the following group structure in your project for some organization in our project.
Move AppDelegate.swift, LaunchScreen.storyboard and Info.plist into the Application group. Inside the Controller group create a new viewController class and name it ‘LockScreenVC’. Create a swift file in the Helper group and name it ‘Theme’. You should now have the following structure.
Pods
We’ll be installing SnapKit using pods. Add the following pod to your podfile.
pod 'SnapKit',:git => 'https://github.com/SnapKit/SnapKit.git', :branch => 'swift-4'
pod 'SwiftIcons', '~> 1.5.1'
We will be using the Swift 4 branch of SnapKit. Swift Icons is optional you don’t have to include it. I just use it for icons.
Show Me The Code !
Let’s start inside AppDelegate.swift. Remove all functions and leave didFinshlaunchingWithOptions. Since our project does not make use of a storyboard we need to tell it how to launch. To do that we will utilize window which is conveniently included for us, but what is window ?
An object that provides the backdrop for your app’s user interface and provides important event-handling behaviors.
Press option and click on UIWindow and you will get a more in-depth explanation of what the window of an application is. Reading the documentation will really help you understanding the API. So let’s create our window and tell the app how to launch.
- We instantiate a window with a frame that takes up the whole screen.
- We then tell the window which class to use as its rootViewController
- Lastly we make the window the key window and also make it visible.
LockScreenVC
Trying to building your project at this point one of two things can happen. One, your project will build and run but all you will see is a black screen this might seem wrong but this means it works. Two, your project will launch and crash at the launchscreen. To fix this clicl on your project under General make sure that the Main Interface is empty like below.
Now to see if the project is running the right view controller I like to set the views background to a bright color, build and then run.
After running you will see…
It works ! Will not be winning any design awards though lol. We will be coming back to Lockscreen.swift but let us make our lives a little bit easier by creating a helper class.
Theme
I am sure you have heard of the DRY principle if you have not it’s simply “DON’T REPEAT YOURSELF” so to adhere to this principle we will be creating a Theme class to manage fonts and the insets for our UI-Components.
- Import UIKit.UIFont , we will only be making use of UIFont so no need to pull in the entire UIKit.
- Create the Theme class. Within this class you can create as many inner classes to your needs to manage different things inside your app. Colors, fonts, insets, padding the possibilities are endless. This gives you a central place to change a value and its automatically adjusted through-out the entire app.
- Our Fonts inner class provides us with the fonts that will be used in the app. The spelling has to be absolutely perfect or else the app will crash. You can go to http://iosfonts.com/ and see the names of fonts.
- Insets basically handles the padding or spacing for UI elements.
Thats of Theme manager completed. 👏🏾
LockScreenVC…again.
Instead of just display UI-Components on the screen lets actually make the app work by displaying the latest time and updating. Before we get there let’s display some things on the screen finally. Import SnapKit and SwiftIcons at the top LockScreenVC. Before we dive in if it’s your first time using an auto-layout DSL try use your knowledge of the storyboard and how constraints operate when creating programmatic constraints. And just like storyboard constraints we need to have a minimum of four constraints that determine the width, height, x and y position of the component.
Creating our background Image
- Why use ‘lazy var’ ? Not going to act like I have all the answers but finding the answers is not that hard. Hint hint.
- I used this image for the background. Rename it to ‘imgBackground’. Start typing “img…” and the image literal will appear in your Xcode pretty cool huh ?
Displaying our background Image
Create a function called setupView this is where we will do all our laying of the UI-Component onto the view.
- So we want the background image to take up the entire screen that is what we are doing here.
- Add the bgImageView to the view as a subview. Always do this first. Repeat after me: I WILL ALWAYS ADD MY VIEWS BEFORE SETTING THEIR CONSTRAINTS.
- So with two lines of code that make absolute sense to me our bgImageView will fill the entire screen. And this will work irregardless of the size class. Run the project now and you’ll see the image reaching all the edges.
Creating our detailContainer
The detail container will be the opaque black stripe at the bottom of the design that contains a number of labels. I just created a UIView with a black background with a alphaComponent of 0.2 (You cal play around with the alpa value to your liking).
Displaying our detailContainer
- We make the width equal to our view.
- And then we pin it’s bottom to the bottom of our safeAreaLayoutGuide. Introduced in iOS 11 the safe area tells us where its safe to place UI-Components.
- Lastly we set its height.
Creating our labels
I won’t spend much time on this as it is very simple. Feel free to leave a comment if anything does not make sense.
Creating the arrow button
This is literally the only place that I made use of the SwiftIcons library but I thought it would be beneficial to show off a cool library that makes working with icons absolutely awesome.
Displaying our UI-Components
I will try not make this section a replica of the the SnapKit documentation but will attempt to rather show how one would use it. Let’s begin by getting that arrowBtn to be positioned bottom right of the view. So how do we do that ?Consider the following things:
- The arrow is inside the detailContainer.
- It is positioned at the bottom right with some padding on the right and some padding below.
- Finally our button must obviously have a width and a height.
- We make our right equal to that of our superView. Note* the superView is not LockScreenVC’s view but it is the detailContainer since we added the arrowBtn to the detailContainer. We then set the inset to move a bit to the left. Think of this as setting the constant on a constraint after pinning it to a component.
- Give the button a width of 50 and a height of 35.
- We then snap the arrowBtn to the bottom of detailContainer and move it up by using our Theme manager again.
Understanding SnapKit
After struggling for a while to understand programmatic constraints I was able to get the hang of it by keeping in mind a few concepts which I would like to share.
- I need a minimum of four constraints. Width, Height, X and Y.
- Firstly choose your ‘ConstraintMakerExtendable’ this is your weapon 🗡. To see what options you have just type ‘make.’ and you’ll see which weapon you can use. As you will see there’s a number of weapons in SnapKit’s arsenal.
- Choose the right weapon for the task. Yes you could probably find a way to get something to work using the wrong ‘ConstraintMakerExtendable’ but you would be working against the grove and find yourself adding way more constraints than necessary. So choose the right weapon! So how do you know which is the right weapon?
- Relationships. Yes you have to build relationships to choose the right weapon. Let’s say you want viewA to be on the left of viewB the relationship you should be creating is viewA’s right should be equal to viewB’s left. Make sense ? Not really. This does not make much sense but visualizing the concept could add much more clarity.
- Distance. After establishing a relationship between the components now next determine the distance you want between them. This can easily be done by setting the inset.
- Size. Next set the components width and height. Just like the storyboard you can set a fixed height and width. You can also use relationships to set priorities and proportions. Looking at set the width type ‘make.width’ Xcode will provide options…Look for one that sounds close enough to what you want and it will probably work. You should be looking at the ‘ConstraintMakerEditable’ usually at the bottom. You can set the width or height equalTo, lessThan or greaterThan any component.
- Proportions. What if I want my view to be half the width of the superView ? Simple just do this:
make.width.equalToSuperview().multipliedBy(0.5)
These are the principles that made me understand SnapKit and get comfortable. Hopefully this can help someone. With these principles you should be able to go on and layout the rest of our UI. The code for the rest of the layout can be found here, but try implement it yourself. This code works and will get the desired UI but it definitely is not the only way it can be done. You can think up your own ways to achieve the same result and that’s the beauty of code. Try find your own solution instead of copy and pasting. When you struggle do research and find out how others have done it.
Displaying The Time ⌚️
Add the above function which will get the current time and display it. New in Swift 4 is that we need to add the ‘@objc’ tag when we want to access the function in a #selector. Next update your viewDidLoad method.
So we setupView, call displayTime and then we create a time scheduler that will call the display time every minute. This will update the time on our view. We now have a cool looking semi-functional mock-up lock screen.
*Disclaimer, there is nothing wrong with using storyboards and don’t let anyone convince you otherwise. There are benefits to using them and benefits to not using them. It is however important for you to be able to do both you will never know what the team you land in will prefer to use. I hope you enjoyed the read, you must have if got all the way to this point 😊 lol.