Hello wonderful community 👋. As a new iOS developer I'm starting to learn how to create views programmatically, it has been tricky to learn how to do this coming from using Storyboards 😅.
In this tutorial, I'll guide you step-by-step on programmatically creating views in iOS. It's an opportunity for me to share what I've learned, with the hope of helping others who are also exploring this area.
Let's start coding! 😀
Starting a new Xcode project
I'm using Xcode version 14.3 and targeting iOS 16
- Open Xcode and click on New Project, we will get this window:
Here we are going to select the simplest template available, iOS > App
- Now let's give some basic information:
- Product Name: It's the name of our app.
- Team: If you have a Apple Developer Account you should select it here, otherwise leave it as None is alright (leave it as None will allow you to test your app only in the simulator).
- Interface: Since we are doing an example with
UIKit
we need to select Storyboard (don't worry we are not actually using them). - Language: Select Swift.
The rest of the options can be unchecked, they won't be used in this simple example.
- Click on Next and select a location on your computer to save the project, finally click on Create.
We now have a simple app ready for us. 🎉
Deleting storyboard references from our project
Now it's time to delete the storyboard file and configurations associated with it.
In this simple project we have two storyboard files, Main
and LaunchScreen
.
We only need to delete the Main
one because this is the one that is loaded once our app starts. We want to provide our own by using code.
- Delete
Main
from the project, when prompt click Move to trash.
- Delete the references of this storyboard, open
Info.plist
and delete the value calledStoryboard Name
by clicking the minus icon.
- Delete the storyboard reference in the target app, this is important because we no longer have the storyboard file so if we try to compile we would get an error because of the missing reference.
Now run your app and you'll get a nice black screen, this mean you deleted the storyboard correctly!.
Configuring programmatically the root window
Now you have an empty screen, nothing was loaded and that's a problem. The storyboard made all of this configuration automatically for you. Now it's your responsibility to configure the screen that will be show when your app starts.
- Open
SceneDelegate.swift
and configure the root window of your app. Locate the method calledfunc scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
.
Once you found it, let's change the method's body with the following:
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
let viewController = ViewController()
window.rootViewController = viewController
self.window = window
window.makeKeyAndVisible()
This code do several things:
- It tries to create a
windoScene
by using the passedscene
object, this object will contain the scene of our app. - It creates a new
window
, this will tell your app to create a windowScene, this object will contain your app's user interface. - It creates a
viewController
, this object is responsible for controlling your view objects. This class is already on your template (`ViewController.swift), so there is nothing special about its name. - Assigning the new ViewController as the root view controller, i.e., the first view controller we are going to create to start our app UI.
- We are assigning the new created window to our class window,
self.window = window
. - Making the window visible on the screen,
window.makeKeyAndVisible()
.
After that configuration your app interface is back to life. If you run it at this point you'll still get a back screen, that's ok because we haven't configured anything on our View objects.
Creating our simple interface programmatically
Now it's time to add some code to make our interface show something on the screen!
ViewController life cycle
The UIViewController
has a specific life cycle, i.e., certain predefined methods are called at specific moments of the object's life. Since we are creating our interface programmatically we need to understand two methods of this life cycle.
-
func loadView()
: This method is used to load our custom views and make some configuration on them before they appear on screen. -
func viewDidLoad()
: This method is called once the ViewController is loaded into memory, here you can create more customization and configuration to your views.
As you can guess, the object first run loadView
and then viewDidLoad
.
Creating an empty UIView
Each ViewController
creates a default empty View, but we want to have our own custom one, so let's start by doing that.
- Create a new file for our new custom view, let's call it
CustomView.swift
and add the following code inside.
`swift
// CustomView.swift
import UIKit
final class CustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .yellow
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
`
Our view inherits from UIView
so we need to define at least these two constructors (init methods). The one we need to focus on is the first one. Here we are adding a background color.
- Create the custom view object and show it on the screen, to achieve this lets open the
ViewController.swift
and inside the class create a new object of our view and assign it as the new view in theloadView
. You should end up with a code similar to this:
`swift
// ViewController.swift
import UIKit
class ViewController: UIViewController {
lazy var customView = CustomView()
override func loadView() {
// we are creating a class property because we may have delegates
// assign your delegates here, before view
view = customView
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
`
One important point to mention, the view property is assigned by default to use all of the phone screen. So we don't need to assign any constrains because of this. The CustomView
will take all of the screen.
Now run your app and you'll see a yellow screen.
At this point, you should have the following files on your project:
Great, now you loaded an empty custom view to your screen!.
Adding a simple label on the empty View
To finish this tutorial let's add a simple label using auto layout.
- Create a
UILabel
property on theCustomView
class and give it some default values like a title and color. You don't need to provide any dimension, we will do this with auto layout. YourCustomView
class should look something like this:
`swift
// CustomView.swift
import UIKit
final class CustomView: UIView {
// 1. Creating the new element
lazy var label: UILabel = {
// internal label, not the same as the external label
let label = UILabel()
label.text = "Hello World"
label.textAlignment = .center
label.textColor = .white
label.backgroundColor = .black
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .yellow
// 2. Adding the new element into the view
addSubview(label)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
`
If you run your code the new label won't appear on the screen, that's because the label has a size of 0 and its position in the screen's position (0,0). This happened because we didn't provide a CGRect
initializer. It's ok, we are going to fix this with auto layout.
- Add auto layout constrains to allow the object to appear on the view (this will give it an area), also remember to set to false the property
translatesAutoresizingMaskIntoConstraints
if we don't do this our view may present problems rendering with auto layout.
Remember that each ui element is represented as a box, so each edge has a name we can refer in our code to assign the constrains.
Your code inside CustomView.swift
should look like something like this:
`swift
// CustomView.swift
import UIKit
final class CustomView: UIView {
// 1. Creating the new element
lazy var label: UILabel = {
// internal label, not the same as the external label
let label = UILabel()
label.text = "Hello World"
label.textAlignment = .center
label.textColor = .white
label.backgroundColor = .black
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .yellow
// 2. Adding the new element into the view
addSubview(label)
// 3. Add the auto layout constrains
setUpLabelConstrains()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setUpLabelConstrains() {
// Needed to avoid auto layout conflicts
label.translatesAutoresizingMaskIntoConstraints = false
// Set the top part of the label to the safe area of the custom view and add a vertical separation of 64 points
label.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 64).isActive = true
// Set the left part of the label to the safe area of the custom view and add a horizontal separation of 18 points
label.leftAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leftAnchor, constant: 18).isActive = true
// Set the right part of the label to the safe area of the custom view and add a horizontal separation of -18 points
// note: if this value it's positive the element will be separate from outside the screen 18 points.
label.rightAnchor.constraint(equalTo: self.safeAreaLayoutGuide.rightAnchor, constant: -18).isActive = true
// Set the height of the label to be equal to 48 points
label.heightAnchor.constraint(equalToConstant: 48).isActive = true
}
}
`
Now let's run the app, a custom label should appear on the screen now. This custom label is a child of the custom view, which was created by the ViewController and set as the default view for our ViewController.
Conclusion
Congratulations, you created an app's ui using only code!. I hope this simple tutorial helps you to understand this topic. There is a lot more to cover but this is a good first step, thank you for reading!.
Until next time.
Top comments (2)
@msa_128 Hi,
Is it possible to add multiple CustomViews to one ViewController?
Hi,
What is the use of this information?
So Xibs, Storyboards and UIKit are old technologies.
If you want talk about the current or future, then this is SwiftUI.