18 Jun, 2019

SwiftUI TabbedView in Xcode 11 Beta 2

SwiftUI TabbedView in Xcode 11 Beta 2

At the time of writing (Xcode 11 Beta 2) SwiftUI's support for the TabbedView component is limited. Last Updated 18 June 2019

TabbedView is SwiftUI's counterpart to UIKit's UITabBarController which is described in the public documentation as:

A view which allows for switching between multiple child views using interactable user interface elements.

TabbedView's setup is briefly showcased in the WWDC19 session 216 SwiftUI Essentials and on the Avocado Toast demo app, the basic usage is shown to be as follows.

In practice, this code doesn't work yet, and it has left many of us scratching our heads. A Tabbed View is after all one of the most common UI patterns in mobile app development. In this article I intend to do a quick tutorial over what is possible to do right now with TabbedView.

Setup some content

In the snippet bellow I have created 2 rather simple View instances. Each one with a Text element. This is the dummy content that we will be loading in our TabbedView as child views.


Build up the TabbedView

With our dummy content in place, we can build our TabbedView.

Here's a line by line by line breakdown of the code:

Line 5 - We declare our TabbedView component. Note that we don't pass a selection parameter for simplicity.

Line 6 - We compose Tab1Content() inside the body of our TabbedView component.

Line 7 - For our Tab1Content() to have a Tab button, we add a tabItemLabel generic instance function.

Line 8 - We compose a Text element by passing it as the parameter in the tabItemLabel generic instance function.

Line 9 - We apply tag() another generic instance function, passing 0 as the parameter. There isn't a whole lot of documentation on this modifier, but it seems to accomplish the purpose of identifying the content inside the TabbedView as well as defining its order of selection. If we switch around the 0 and 1 values in the tag() modifiers we see that the initial selection is changed.

Line 10 - 14 Repeat the same steps for Tab2Content()

This is quite different from what is shown in the WWDC session. There are 2 main differences:

Tag modifier

In the WWDC session, no tag() modifier is used. Without it though, TabbedView fails to respond to the taps on the tabs, as seen in this Stackoverflow question.

tabItemLabel

In the WWDC session tabItemLabel appears to have a different signature where it is possible to specify an Image as well as a Text element to form the tab button. This seems to be inside a body delimited by curly brackets that is not possible to write today. The public documentation on TabbedView says:

TabbedView only supports tab items of type Text, Image, or a LayoutView of Image and Text. Passing any other type of view will result in a visible, empty tab item.

But a search for LayoutView finds no results. For the time being it seems that this functionality is limited and only allows a simple Text to be added to the tabs.

Additionally, passing an Image instance instead of a Text instance, doesn't work yet either.


TabbedView on tvOS

Because of SwiftUI's flexibility it is possible to use the code above on tvOS. The layout shown above renders like this.

TabbedView renders with some important layout differences to accommodate the totally different experience provided by an Apple TV device. Under the hood, TabbedView is still rendering as a UITabBarController.

The rendering of the tab buttons is not ideal as the color of the selected text makes it impossible to distinguish from the background.


And there you have it, the minimum setup possible for TabbedView in SwiftUI. I look forward to the next release in July where I hope to see a more complete implementation of TabbedView.

Sample project

You can find a finalized sample project at https://github.com/piterwilson/MyTabbedView

Sources and Further reading