VisualKit: creating a UI Framework

Victor Baro
Job&Talent Engineering
8 min readApr 10, 2017

--

This post covers how the iOS team has created and dealt with a UI Framework, its structure and relation with the main project, as well as the benefits and downsides of this decision. Don’t miss the post on the same topic from the android team!

About a year ago, the mobile team at Jobandtalent was presented with a huge project. This new project had many new features, screens, interactions… The design team took this opportunity to improve their workflow by introducing atomic design, which defines a blueprint, with buttons, controls, cells, etc. That is, to create new screens they only used existing components and combinations of them.

Atomic design example

Based on this concept, the design team at Jobadntalent created their own design system.

Jobandtalent design system example

We applied the atomic design philosophy in our project by creating new standard components and using them in multiple scenarios. This approach allowed us to write reusable UI code.

VisualKit is Jobandtalent’s UI Framework. In a nutshell, VisualKit is a big modular package of views and controls where each one of them can be easily themed and modified to fit the design, just like playing with Lego.

VisualKit Structure

VisualKit contains views and controls, including blank slates, buttons, loaders, segmented controls, switches, cells, etc. All new visual components are created in VisualKit.

Let’s have a look at an example on how we break down a screen into different components.

Forget about the navigation and tab bars, and let’s focus on the main tableView.

Each cell has three different sections:

  • Header: contains the avatar, labels, a disclosure and a red dot (optional).
  • Special label: we call it ChipView and indicates state. It can be red, green or yellow.
  • Information breakdown: contains labels displayed in two columns and multiple rows.

VisualKit declares any view needed from the main project as public.

In the previous case, each individual section, as well as the cell (which is a combination of the 3 sections) will be declared public. This allow us to reuse each section throughout the main project. As shown below, the same cell is used multiple times.

If we make the cell modular, we only need to code it once. We simply need to:

1. Create each individual component (avatar, label, disclosure..)

2. Make the container view capable of rendering itself in different configurations by combining its individual components. StackViews are a great tool for this modular approach.

For example, to create the header, we use a horizontal StackView that contains the red indicator, the avatar, another vertical StackView and the right disclosure. The vertical StackView contains the two main labels.

VisualKit makes the header publicly available and configurable from the main project.

The API for components like the header is very simple and resembles UIKit standard components.

This view is not only ready to be used from the main project, but also from within VisualKit itself to generate more complex views.

There is only one particular property, though, it is worth to pay attention to: style.

Styles: Conforming to Styleable protocol

In VisualKit each view conforms to the following protocol:

It is a simple yet powerful protocol that makes all components behave equally. Furthermore, each component must define its own styles.

For example, our ChipView has three different styles. To make the ChipView conform to our Styleable protocol, we first need to define each style.

We do so by creating a public struct, where we define each aspect to be customised by each style. This same struct will also have different class initializers for the different styles.

The struct initialiser is not publicly available. This restricts anyone from the outside to create and set new styles.

Last, we can extend our chipView to conform to our protocol (Note how we specify the type, in this case, ChipStyle):

This is useful, particularly when all your components conform to the same protocol. Now, from the main project, we can simply do:

And we are done.

Create each component to adapt itself to change between different styles is hard work, but it pays off. Once is set up, it is incredibly easy to create new styles.

The same applies for buttons, cells, and may many other components. It is also useful for UIKit classes like UILabel. Here is an example:

Styles: Colors and Fonts

We created two abstractions over UIColor and UIFont in Visualkit, ColorPalette and FontBook. They are simple but they get the job done.

ColorPalette and FontBook

Let’s start with FontBook. This class manages the full set of fonts available in the Jobandtalent app. We only use the fonts designers have previously defined. Nevertheless, there is a public function that takes a name and a size and returns the correct Font.

To use it, for example, we call FontBook.extralarge

The ColorPalette is, again, a series of defined colors. The problem with colors is the alpha value. Even if your designer uses UIColor.blue there is a wide range of colors that they can choose just by playing with the opacity. This is why all our colors only have seven alpha possibilities + the base color (alpha = 1).

In the project, we only use colors defined inside the ColorPalette like this: view.backgroundColor = ColorPalette.dark.alpha80

Project example

One of the nicest “side effects” of having a separate UI Framework is to reuse it in different projects. We created a new specific project to play with VisualKit.

The example app serves many different purposes:

  • To develop our controls outside the main project. VisualKit is all about UI: it is quicker to test controls and see them in action without having to navigate to a specific screen buried in the app. Playgrounds are very useful for that.
  • To help the design team validate new components. The app includes Flex, which is awesome for tweaking values in realtime.
  • To be used as a “library”. Once the framework started to grow, we needed a quick visual reference to each individual component.

Creating and Working with a framework

Our project already managed dependencies using Cocoapods. Once we decided to create this framework, it made sense to take advantage and develop it as a private pod (check this brilliant guide for more details on how to set it up).

I would like to give you my 2 cents on how easy/hard quick/slow things can become when you move most of your UI classes to an external source:

  • Cocoapods is a great tool. For instance, when using developments pods, you are able to modify them within your project. However, every time you create a new file, you need to run pod install and obviously let your team know about it. We do not have it versioned as it is not mature enough, but it is definitely something to consider.
  • Public, internal, open and private become more powerful than ever. When working on a project, you hardly ever use public. By default (internal) all files can see each other. When you encapsulate your classes in a framework, only those (classes, functions, protocols) marked as public will be available. This simple fact makes you more aware when designing your classes’ APIs and gives you more power (now you have a three layer access).
  • You need to import VisualKit in (mostly) every view controller. We could use the .pch but VisualKit should only be available from the UI Layer. Other internal layers do not need to know or deal with it.

“Opensourcing” VisualKit

Opensourcing VisualKit as it is today would be useless: it is coupled to our app’s design.

However, everytime we create a new component we make it as an isolated instance. From VisualKit, we have already released two components: AnimatedTextInput and CardStackController. We will release new components as soon as they are ready.

Everyone on the iOS team agrees that having VisualKit as a framework was a great decision. It made us work faster and respond quicker to design changes.

Designers and developers working together

We could argue about the usefulness of having these abstractions over colors and fonts, or having styles for each component. Is this worth it? Can’t I just go ahead and do that on the storyboard/xib or in code every time I create a new view?

Obviously you can. But we should be able to respond fast to any design change. Maybe designers want a brighter blue, a new font or a faster animation. It is difficult to foresee what will change in the future, but working alongside designers can help you and save you time.

Our solution tries to mimic our designers approach. We create screens in a very similar way as they do. If they update the color palette, we can update it too and everything will “react” to this change. It shouldn’t be a hassle for developers to introduce a new font across the app.

Working alongside designers helped us understand their design process. In turn, designers also learnt from us, finding new solutions to overcome technical restrictions.

As a final note, it might not be a developer’s job to be part of early design decisions. It is usually managed by the project managers and designers. However, during this time I have experienced that being part of that process as early as possible, will really help your team.

Thanks to Luis Recuenco, Daniel García, Rubén Mendez, Rafa Aguilar, Xavier Jurado, Pol Quintana, Daniel Martín, Alexis Santos, Isaac Roldán, Andrés Brun and Ramón Argüello for contributing and making this possible.

— — — — — — — — — — — — — — — — — — — — — — — — —

Bonus: Playgrounds!

I love playgrounds, and live updates give us superpowers. I use them all the time when creating a new component for VisualKit.

Here is a simple template I use to start a new Playground.

I have speed-recorded myself creating a new component. You can find it here. I believe it is a good example of a VisualKit component (atom), that we have reused multiple times as part of other views (molecules).

We are hiring!

If you want to know more about how is work at Jobandtalent you can read the first impressions of some of our teammates on this blog post or visit our twitter.

--

--

iOS Developer @onUniverse. Previously @Dexcom @jobandtalentEng. @produkt co-founder