Adding an Instructional Overlay for first time users to your app in iOS
Sometimes called Coachmarks, a Wizard, or an Onboarding Flow, this common UX pattern is used to guide first time users to an app on its features in your UI.

Here’s a quick and simple way to implement this pattern:
private func buildButton(with title: String) -> UIButton {
let button = UIButton(type: .system)
button.backgroundColor = .systemOrange
button.setTitle(title, for: .normal)
return button
}
override func viewDidLoad() {
super.viewDidLoad()
let buttonText = "Put me in coach!"
let button = buildButton(with: buttonText)
button.translatesAutoresizingMaskIntoConstraints = false
let overlay = UIView(frame: .zero)
overlay.translatesAutoresizingMaskIntoConstraints = false
overlay.backgroundColor = UIColor.black.withAlphaComponent(0.5)
let coachButton = buildButton(with: buttonText)
coachButton.translatesAutoresizingMaskIntoConstraints = false
coachButton.isUserInteractionEnabled = false
let coachLabel = UILabel(frame: .zero)
coachLabel.translatesAutoresizingMaskIntoConstraints = false
coachLabel.textColor = .white
coachLabel.text = "Get player in the game"
view.addSubview(button)
view.addSubview(overlay)
view.addSubview(coachButton)
view.addSubview(coachLabel)
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
coachButton.centerXAnchor.constraint(equalTo: button.centerXAnchor),
coachButton.centerYAnchor.constraint(equalTo: button.centerYAnchor),
coachLabel.centerXAnchor.constraint(equalTo: coachButton.centerXAnchor),
coachLabel.centerYAnchor.constraint(equalTo: coachButton.bottomAnchor, constant: 20),
overlay.topAnchor.constraint(equalTo: self.view.topAnchor),
overlay.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
overlay.leftAnchor.constraint(equalTo: self.view.leftAnchor),
overlay.rightAnchor.constraint(equalTo: self.view.rightAnchor),
])
}
The idea here is that you have a duplicate button on top of a semi-transparent overlay. We use Auto Layout to constrain coachButton to the real button, and we also disable isUserInteractionEnabled since we don’t actually want the user to be able to select it in this flow.

Also, note how we’re using buildButton(with:) to instantiate the buttons so we make sure we’re actually constructing the buttons the same way for both button and coachButton.
Did you find this helpful? Get updates when I post more like this by subscribing to the Nerd Tower newsletter.