Focus in tvOS


As a developer in the Apple ecosystem, it’s always exciting to have a new device to work on. With the release of the fourth generation Apple TV, we have a new SDK that will feel familiar to iOS developers, but also comes with some new ideas.

New Design Principles

When Apple released iOS 7, they overhauled the look and feel of the entire operating system. They used three guiding principles to achieve the new design: deference, clarity and depth. With the release of tvOS, we have three new design principles:

  • Connected
  • Clear
  • Immersive

tvOS’s clear and immersive principles convey similar ideas as iOS’s clarity and deference, but what’s this connected principle about? The key to understanding this principle is in the way users interact with their Apple TV. Unlike iOS or OS X, users always experience the device at a distance through a remote control. Apple wants to emphasize that users should feel just as intimately connected to their TV as they would their iOS device, which they can directly manipulate with their fingers. For an example of this principle in action, see how slight movements on the Siri Remote’s touch surface will cause a parallax effect on the icons on the home screen. For a more detailed discussion of these principles, see the Apple TV HIG.

The Focus Paradigm

To give users the sensations of clarity and connectedness, tvOS uses the concept of focus. This concept is similar to the cursor in OS X. It’s a representation of what the user intends to interact with. This paradigm is very different from the way we would think about interaction on iOS. Let’s look at an example to see why:


We can tell that the App Store icon is in focus because it is enlarged and has a drop shadow. If we were to swipe to the left on the Siri Remote’s touch surface, which way would the focus go? What would happen on iOS if we swiped on a similar interface?

On iOS, swiping left on a list of items would typically cause all the items to scroll to the left. On tvOS, we don’t do this same ‘grab the content and move it’ gesture. We move the focus instead. Swiping left in this state will move focus to the TV Shows icon, causing that icon to grow and the App Store icon to shrink.

The Focus Engine

To provide a consistent experience across all apps, tvOS uses a focus engine to manage all changes in focus. It’s important to understand how the focus engine works to create apps with the correct look and feel.

Users can move focus in the up, down, left, right, or any of the diagonal directions. Let’s see how the Focus Engine manages these changes in an example scene:


In our example, we have a scene with a button in the center. The center is surrounded by additional buttons that represent all possible directions for changes of focus.

When the user makes a gesture, the focus engine will run a query against the UIView hierarchy to determine which UI element should be focused next. Here’s an example where we start with the focus on the ‘Center’ button:

Swipe right, starting in the center

Swipe right

This diagram can help us visualize how the focus engine works. The engine knows to move focus to the ‘Right’ button because that button is in the bounding box between the ‘Center’ button and the edge of the screen.

Swipe left, starting from the right side

Move back to the center by swiping left

When we swipe to restore the focus to the center button, we get another similar query. A new bounding box is defined, again in the direction of the user’s gesture. Notice how there’s two buttons that could be selected, but the focus engine selects the closest one.

Here’s another example, this time with a diagonal gesture:


Swipe down and to the right

In this example we can see how the focus engine creates a bounding box that starts on the view’s corner when the gesture is diagonal.


Move back to the center by swiping up and to the left

Similar to the previous gesture, when there are multiple elements within the bounding box, the focus engine will select the closest one.

Redirecting Focus

In some instances, the focus engine’s bounding box approach won’t work. Let’s look at another example scene:


Here we’ve positioned two buttons diagonally. If the focus is on Button A, and our user swipes right, nothing will happen. It’s intuitively clear that the focus should move to Button B, but the focus engine doesn’t select that button because it’s not inside the bounding box.

The solution to this problem is to add a UIFocusGuide. This class will allow us to place an invisible box in a location where the focus engine will detect it. Our focus guide will then refer the focus engine to a view elsewhere in the scene. Let’s look at how to do this in code:

import UIKit
class ViewController: UIViewController {
@IBOutlet var buttonA:UIButton!
@IBOutlet var buttonB:UIButton!
override func viewDidLoad() {
let focusGuide = UIFocusGuide()
focusGuide.preferredFocusedView = buttonB
view.addConstraint(NSLayoutConstraint(item: focusGuide,
attribute: .Width,
relatedBy: .Equal,
toItem: buttonA,
attribute: .Width,
multiplier: 1,
constant: 0))
view.addConstraint(NSLayoutConstraint(item: focusGuide,
attribute: .Height,
relatedBy: .Equal,
toItem: buttonA,
attribute: .Height,
multiplier: 1,
constant: 0))
view.addConstraint(NSLayoutConstraint(item: focusGuide,
attribute: .CenterX,
relatedBy: .Equal,
toItem: buttonB,
attribute: .CenterX,
multiplier: 1,
constant: 0))
view.addConstraint(NSLayoutConstraint(item: focusGuide,
attribute: .CenterY,
relatedBy: .Equal,
toItem: buttonA,
attribute: .CenterY,
multiplier: 1,
constant: 0))
//MARK: – UIFocusEnvironment
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
//TODO: update the 'preferredFocusView' of our focusGuide depending on which view is now in focus

view raw
hosted with ❤ by GitHub

In the above code sample, we place the focus guide to the right of Button A and above Button B. When the user is focused on Button A and they swipe right, the focus engine sees this:


The focus engine finds an instance of UIFocusGuide

The focus engine will select our guide, and because the guide has Button B as its preferredFocusedView, Button B will gain focus.

Debugging Focus

All of the diagrams in this post were generated using Xcode. To generate these diagrams, we need to perform a quick look on an instance of UIFocusUpdateContext. To get a reference to one of these update contexts, override either the shouldUpdateFocusInContext or didUpdateFocusInContext: method in any class that implements the UIFocusEnvironment protocol. UIView and UIViewController both implement this protocol, which makes it easy for us.

See the above sample code for an example of how to write this override.

Once we’ve got a diagram open in quick look, we can open it in the Preview app. This allows us to save it or share it with other members of our team.

More to Learn

As usual, this is just the tip of the iceberg. There’s still lots of exploring to do on this new platform. But after this overview of the focus engine, we should have the necessary tools to dig further into tvOS.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s