Codecademy Team

Toolbars and Sheets

This article will teach you the basics of toolbars and sheets.

Introduction

In this article, you will learn:

  • What a toolbar in Swift is
  • How to create a toolbar
  • What a ToolbarItem is and how to add them to a toolbar
  • To provide a ToolbarItem a specific placement
  • What is a Sheet
  • How to present a Sheet
  • How to present a toolbar inside a sheet

Let’s begin by creating a project that will showcase the capabilities of toolbars and sheets. Your final project will resemble the following video.

Final Project Video

Creating the project

To begin, open up Xcode. You should get a window that resembles the image below.

Xcode Window

In the center of the Xcode window, you will see Create a new Xcode project. Go ahead and click on this.

Project Type

Next, you should see project templates. App should already be selected; if not, go ahead and click that. At the bottom right, click on Next. You will now insert some information regarding the application.

  • Product Name: ToolbarProject
  • Team: None is acceptable here; If you have a team identifier, feel free to use it
  • Organization Identifier: This is usually your reverse domain; for now, com.YourName is appropriate
  • Bundle Identifier: It should be automatically filled provided your Organization Identifier + Product Name.
  • Interface: Be sure to select SwiftUI
  • Life Cycle: SwiftUI App
  • Language: Swift
  • Use Core Data is OFF
  • Include Tests is OFF

Project Settings

Now select where you would like to save the project. Do not select Create Git repository on my mac. Git is a popular tool used for version control. If you do want to use Git for version control, select the option and learn more about Git here.

Once you select a location, click on Create. Your project should look similar to the image below.

Created Project

Fantastic, you’re now ready to start building toolbars and displaying sheets in your project!

What is a toolbar?

SwiftUI’s toolbar modifier allows for placement of views along the top or bottom space of a view. For a toolbar to work properly, it must be embedded in a NavigationView.

Here is a view that contains a toolbar with two buttons at the top of the view.

Example Toolbar

Create a toolbar

To properly attach a toolbar, first create a NavigationView. Within it, embed Text("Hello World").

import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Hello World")
}
}
}

According to the Apple docs, a toolbar wraps views just like a VStack or NavigationView. A toolbar is written as:

NavigationView {
Text("Hello World")
.toolbar {
// Views go here
}
}

Let’s use the same methodology to create a toolbar in the project. Also, change Text("Hello World") to Text("Initial View").

ContentView.swift

import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Initial View")
.toolbar {
}
}
}
}

Great work! You created your first toolbar. Your view should match the image here.

Transparent Toolbar

The view looks the exact same!? That’s because the toolbar is by default a transparent container.

Let’s add some buttons to the toolbar to make it useful. You can use a ToolbarItem to display a button on the toolbar. Let’s take a look at ToolbarItem.

What is a ToolbarItem?

According to the Apple docs, SwiftUI’s ToolbarItem represents a container for placing one item on a toolbar. If you want more than one item, you will have to use multiple ToolbarItems. ToolbarItems usually contain a Button, Text, or Image. A ToolbarItem is written as so:

NavigationView {
Text("Hello World")
.toolbar {
ToolbarItem {
// Items goes here
}
}
}

Let’s use the same methodology to create a ToolbarItem in the project. Inside the ToolbarItem, place a Button using the Button(action:, label:) constructor with an empty action and Image(systemName: "gear") for the label.

ContentView.swift

import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Initial View")
.toolbar {
ToolbarItem {
Button(action: {
}, label {
Image(systemName: "gear")
})
}
}
}
}
}
}

Fantastic! You added a ToolbarItem to your toolbar. The ToolbarItem contains a button. Your preview should match the one here.

Initial view with gear without placement

But, what if you want to put the button on the other side of the toolbar? You can do so by providing a specific placement for your item. Let’s see how it’s done.

ToolbarItem placement

A ToolbarItem can be given a specific placement onto the toolbar. The placement is determined by the optional placement parameter for ToolbarItem which takes in a value of type ToolbarItemPlacement. If there is no placement given, it will default to the top right corner. You can place a ToolbarItem in the top left corner by passing in .navigationBarLeading with the given code:

NavigationView {
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
// Button goes here
}
}
}

Since Xcode can safely assume you will place an instance of ToolbarItemPlacement inside the placement argument using type inference, you can type . in the argument and the full list of ToolbarItemPlacement options will display. Here is an example of that working (disregard the error as it will disappear on selection):

Type Inference

In your project, assign your current ToolbarItem a placement of .navigationBarLeading.

ContentView.swift

import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Initial View")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
}, label {
Image(systemName: "gear")
})
}
}
}
}
}

Great! You moved your gear button to the top left corner of the view using the placement: ToolbarItemPlacement input parameter.

Your preview should match the one here.

Xcode Window

Now, let’s present a new view on the Button tap.

What is a sheet?

SwiftUI sheets are used to present a new view over an existing one. Think of this as a stack of papers. You can have multiple sheets on top of one another, and the middle one can be accessed by removing the ones above it.

Here is an example of a sheet being displayed.

Sheet being displayed

How to present a sheet

A sheet, like the one above, is presented using a binding of a Bool. As the boolean changes, the binding will change the view. If the Bool is true, the sheet will be presented. When it is set to false, the sheet will dismiss. The Bool is usually stored in the structure as an @State variable to be able to modify the view as it changes.

A sheet can be presented using the following:

@State var isPresenting: Bool = false
NavigationView {
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Some Button") {
isPresenting = true
}
}
}
.sheet(isPresented: $isPresenting) {
// View to display goes here
}
}

The sheet takes in isPresented: $isPresenting which is the binding Bool for the view to keep track of. When the isPresenting is set to true on the button tap, the sheet will display the view inside the sheet.

Let’s add a sheet to your project. Inside the sheet, display a NavigationView. Inside the NavigationView, display a Text("Settings Page"). Don’t forget to set the isPresenting property to true when the button is tapped!

ContentView.swift

import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Initial View")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
}, label {
Image(systemName: "gear")
})
}
}
.sheet(isPresented: $isPresenting) {
NavigationView {
Text("Settings Page")
}
}
}
}
}

Great work! You added a sheet that contains a Text("Settings Page"). You are able to see the sheet when the Button is tapped because isPresenting is set to true. You can also dismiss the sheet by sliding the view downwards.

Your preview should match the one here.

Sheet being Displayed After Completion

Toolbar within a sheet

But, what if you wanted to present a toolbar inside the sheet that you are displaying? You would implement the same strategy as you’ve done previously by adding a NavigationView inside the sheet and then add a toolbar inside the NavigationView.

In your project, since there is already a NavigationView inside the sheet, attach a toolbar that contains a ToolbarItem. Place a Button("Save") {} inside the ToolbarItem with no specified placement.

ContentView.swift

import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
Text("Initial View")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
}, label {
Image(systemName: "gear")
})
}
}
.sheet(isPresented: $isPresenting) {
NavigationView {
Text("Settings Page")
.toolbar {
ToolbarItem {
Button("Save") {}
}
}
}
}
}
}
}

Fantastic! The toolbar displays a sheet that contains a toolbar. The second toolbar contains a button titled "Save" that doesn’t have an action, yet.

Your preview should match the one here.

Toolbar inside sheet inside toolbar

Conclusion & review

Great work! In this article, you’ve covered toolbars and sheets. You created a miniature project that simulates an application that displays a settings page from a button tap on the toolbar.

Here’s a recap:

  • A toolbar allows for placement of buttons along the top or bottom space of a view

  • You create a toolbar using the following code snippet:

    NavigationView {
    Text("Hello World")
    .toolbar {
    // Views go here
    }
    }
  • A ToolbarItem represents a container for placing one item on a toolbar

  • A ToolbarItem is created using the following code snippet:

    NavigationView {
    Text("Hello World")
    .toolbar {
    ToolbarItem {
    Button("Toolbar Item Button")
    }
    }
    }
  • A ToolbarItem placement is indicated using the placement: ToolbarItemPlacement parameter. The list of options are available on Xcode or on the Apple docs.

  • A sheet is used to present a new view over an existing one.

  • A sheet is presented using the following code snippet:

    @State var isPresenting: Bool = false
    NavigationView {
    Text("Hello World")
    .toolbar { /* Toolbar */ }
    .sheet(isPresented: $isPresenting) {
    // Views go here
    }
    }
  • A toolbar can be presented inside a sheet using the following code snippet:

    @State var isPresenting: Bool = false
    NavigationView {
    Text("Hello World")
    .toolbar { /* Toolbar */ }
    .sheet(isPresented: $isPresenting) {
    NavigationView {
    Text("Settings Page")
    .toolbar {
    ToolbarItem {
    Button("Some Button")
    }
    }
    }
    }
    }