---
title: 'Building iOS Interfaces: A Custom Button'
teaser: It's about time to apply what we've learnt so far to implement a custom button
  and introduce some new concepts along the way.
tags: ios,design,mobile,swift
author: Reda Lemeden
published_on: 2016-03-03
---

*This article is Part 3 of the __Building iOS Interfaces__ series which tackles
*the how and why of implementing iOS designs without prior native programming
*experience--perfect for Web designers and developers. You can find the previous
*articles here: [Part 1][primer] -- [Part 2][views].*

After having introduced [the technology stack][primer] and taken a closer look
at [views], it's time to tackle a concrete, all-too-common example of UI
customization: buttons.

I've covered this topic [in the past][Taming UIButton], but we will tackle it
afresh this time, focusing on the approach that you'd most likely use if you
were to accomplish this task today.

Let's pick up [the example project][download link] from where we left off last
time. If you run the project in Xcode, you will see a lonely, off-center
button in the simulator. Let's start there.

### Buttons in iOS

Since iOS 7, stock buttons have lost their borders, filled backgrounds,
and shadows. Let's pretend that this new look doesn't fit the design direction
that we're going after; we want our rounded-corner, filled button look
back.

![Button Design](https://images.thoughtbot.com/building-ios-interfaces-custom-button/ButtonResult.jpg)

If you are used to graphic editors, the most intuitive course of action is to
select the element you want to change—the button—then modify its
attributes on the fly until you get the desired result.

Let's see how far this approach can take us in Xcode. In the project navigator,
click the storyboard file and select the button. Select the *Attributes
Inspector* (a tiny slider icon) from the *Utilities* sidebar to the right to see
the customization options available in Interface Builder. If any of the sidebars
are hidden, make sure to turn them on first before proceeding.

![Button Attributes](https://images.thoughtbot.com/building-ios-interfaces-custom-button/AccessButtonAttributes.png)

At the bottom of the attribute list, there is a *View* section with a
*Background* attribute. Change the background color to a hue of blue to your
liking and the tint color right below to white. Resize the button to give the
text a bit of breathing room, and change the font weight to *Medium* in the
*Button* section above.

![Change Font](https://images.thoughtbot.com/building-ios-interfaces-custom-button/ChangeFont.png)

So far, so good. The only thing left is changing the corner radius, which
would probably be one more attribute to change, right? Sadly, that is not the
case (as of Xcode 7).

### Layers

Up to this point, we've been dealing with views, and views only. In reality,
most view classes in *UIKit* do not expose properties that you come to expect
when designing user interfaces. Corner radiuses and borders are two notable
examples. This is where *layers* (represented by the *CALayer* main class) come
into play.

Put simply, *every* view in iOS is backed by a layer object that is responsible
for drawing what you see on the screen and managing its geometry (origin,
position, rotation, etc). Several methods and properties on *UIView* subclasses
act as a thin wrapper over their layer counterparts.

While a view can have only one *backing layer* (or *root layer*), you can insert
any number of *sublayers* into its layer stack, effectively creating a *layer
hierarchy*, where layers are nested within other layers at specific positions.

![Views & Layers](https://images.thoughtbot.com/building-ios-interfaces-custom-button/ViewLayer.jpg)

Back to our example. The easiest way in iOS to change the corner radiuses of a
view is through the `cornerRadius` property of its root layer. Since this
property is not exposed directly by the view or in Interface Builder, we will
have to take matters into our own hands and write some Swift code. So, where do
we start?

### Models, Views, and Controllers

Although views are going to be the bread and butter of your work as an iOS
designer, you need to get familiar with a couple more concepts to do things the
Apple-endorsed way.

If you look at the Project Navigator to the left, you should see a
`ViewController.swift` file that was generated when we created the project. Open
the file in the editor by selecting it, and proceed to delete the comments
(lines that start with `//`) and the `didReceiveMemoryWarning()` section. The
end result should look like this:

```swift
import UIKit

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
  }
}
```

Xcode creates this file by default because Apple recommends following the *MVC*
pattern when building iOS apps. MVC is an acronym for *Model, View, Controller*
and is a methodology that organizes code in a project based on three different
roles:

- *Model*: The data and logic layer of the app. There are no default model
  objects since they are different from one app to another.
- *View*: The interface that the users sees and interacts with. We've already
  covered views in the [previous article][views].
- *Controller*: The glue between models and views. It ensures that the view
  reflects the state of the app and also translates user input into actions that
  manipulate this state.

![MVC](https://images.thoughtbot.com/building-ios-interfaces-custom-button/MVC.jpg)

Our `ViewController` is a subclass of `UIViewController`, the base view
controller class in iOS. As we noted in the [previous article][subclassing], a
subclass inherits all of the properties and methods of its superclass. In Swift,
you can create a new subclass using the following declaration syntax:

```swift
class SubclassName: SuperclassName { }
```

Now let's take a closer look at what's happening inside the subclass declaration
in our example:

```swift
override func viewDidLoad() {
  super.viewDidLoad()
}
```

There are a couple of interesting things going on in this code snippet, but
we'll probably save the details for later to keep things digestible. Suffice it
to say that we're overriding the `viewDidLoad()` method on the superclass
(`UIViewController`) using the `override` keyword, then falling back to the
superclass's implementation of the same method using the keyword `super`. It is
also worth noting that `viewDidLoad()` is a method that gets automatically
called by the system when the view data is loaded into memory.

In short, we can add custom code that will execute when our view loads. There is
one bit that is still missing however: how do we refer to our button from within
the view controller? Enter *outlets*.

### Outlets

Outlets are the bridge between Interface Builder and code. Each control you
place in IB can be represented by an outlet in your Swift files. An outlet
reference can be used to modify the look of these controls and update the data
they present.

To add an outlet, we need to use the Assistant Editor in Xcode, then hold `Ctrl`
while dragging a connection line from the control in IB to the source code file
where we want to create the outlet:

![Outlet](https://images.thoughtbot.com/building-ios-interfaces-custom-button/Outlet.gif)

Make sure you release the connection outside the `viewDidLoad()` method,
otherwise you will get errors. If done correctly, you should see this line added
in the view controller source code:

```swift
@IBOutlet weak var roundedCornerButton: UIButton!
```

Now that we have a way to reference our button, we can access its properties and
change them from within the view controller. But how do we do that?

### Rounding Them Corners

In Swift, properties can be accessed using *dot notation* of the format
`someObject.someProperty`. For instance, to get the root layer of our button we
can use the `roundedCornerButton.layer` syntax. Similarly, we can get the
`cornerRadius` property of the root layer by adding `.cornerRadius` to the
previous notation.

To set a new value, we can use the same syntax as above and add an equals sign
to *assign* a new value:

```swift
override func viewDidLoad() {
  super.viewDidLoad()
  roundedCornerButton.layer.cornerRadius = 4
}
```

Before running the app to preview the results, let's make sure the button
remains centered in the screen using Auto Layout (more on that later). Make sure
the button is centered in the view by manually moving it until you see 2 blue
perpendicular guides, then select the *Add Missing Constraints* from the Auto
Layout Issues menu at the bottom right of the work area:

![Add Constraints](https://images.thoughtbot.com/building-ios-interfaces-custom-button/CenterAutolayout.gif)

Voilà! Run the app to see our button in full glory. You can download the
updated project [here][completed project].

![Final Result](https://images.thoughtbot.com/building-ios-interfaces-custom-button/ButtonOutcome.png)

### Wrap up

This exercise can hopefully serve as a good example of how you can use both
Interface Builder and Swift to customize a stock iOS control. In the future,
we'd like to focus on workflows that minimize the back and forth between the
two.

[completed project]: https://github.com/thoughtbot/Swiftbot/archive/b4e140f1f23bc103a490949140dcc0b2f1deb2f8.zip
[download link]: https://github.com/thoughtbot/Swiftbot/archive/1e5f4265fb39aad6970dab88d97e0b106cd3cf5e.zip
[primer]: https://thoughtbot.com/blog/building-ios-interfaces-swift-primer
[subclassing]: https://thoughtbot.com/blog/building-ios-interfaces-views#uiview
[Taming UIButton]: https://thoughtbot.com/blog/designing-for-ios-taming-uibutton
[views]: https://thoughtbot.com/blog/building-ios-interfaces-views
