Toolbar in SwiftUI

DevTechie Inc
May 11, 2023

SwiftUI’s toolbar modifier allows us to place bar button items in navigation bar or in the bottom bar.

In this article, we will explore toolbar in SwiftUI.

We create items in toolbar using ToolbarItem. ToolbarItem is a model that represents an item which can be placed in the toolbar or navigation bar.

Let’s create our first toolbar.

struct DevTechieToolbarExample: View {
    var body: some View {
        NavigationStack {
            VStack {
                Text("Learn iOS Development")
                Text("with")
                Text("DevTechie")
            }
            .navigationTitle("DevTechie.com")
            .toolbar {
                ToolbarItem {
                    Button {
                        
                    } label: {
                        Image(systemName: "plus.circle.fill")
                    }
                }
            }
        }
    }
}

We can add more than one button on one side with the help of ToolbarItemGroup. ToolbarItemGroup is a model that represents a group of ToolbarItem which can be placed in the toolbar or navigation bar.

struct DevTechieToolbarExample: View {
    var body: some View {
        NavigationStack {
            VStack {
                Text("Learn iOS Development")
                Text("with")
                Text("DevTechie")
            }
            .navigationTitle("DevTechie.com")
            .toolbar {
                ToolbarItemGroup {
                    Button {
                        
                    } label: {
                        Image(systemName: "plus.circle.fill")
                    }
                    Button {
                        
                    } label: {
                        Image(systemName: "minus.circle.fill")
                    }
                }
            }
        }
    }
}

We haven’t added any action to our buttons so they don’t do anything. Let’s change that and add a counter so we can increase/decrease the value on toolbar button tap.

struct DevTechieToolbarExample: View {
    @State private var counter = 0
    var body: some View {
        NavigationStack {
            VStack {
                Text("Learn iOS Development")
                Text("with")
                Text("DevTechie")
                Text("Count: \(counter)")
                    .font(.largeTitle.bold())
                    .foregroundColor(.white)
                    .padding()
                    .background(.indigo, in: RoundedRectangle(cornerRadius: 20))
                
            }
            .navigationTitle("DevTechie.com")
            .toolbar {
                ToolbarItemGroup {
                    Button {
                        counter += 1
                    } label: {
                        Image(systemName: "plus.circle.fill")
                    }
                    Button {
                        counter -= 1
                    } label: {
                        Image(systemName: "minus.circle.fill")
                    }
                }
            }
        }
    }
}

We can define placement for the toolbar item with placement parameter. ToolbarItem and ToolbarItemGroup both takes the placement parameter and work the same. We will add placement for toolbar item group.

ToolbarItemGroup(placement: .bottomBar)

If we want bar buttons at the leading and trailing edges, we can do that by adding two toolbar items and setting placement for both of them.

.toolbar {
    ToolbarItem(placement: .navigationBarLeading) {
        Button {
            counter += 1
        } label: {
            Image(systemName: "plus.circle.fill")
        }
    }
    ToolbarItem(placement: .navigationBarTrailing) {
        Button {
            counter -= 1
        } label: {
            Image(systemName: "minus.circle.fill")
        }
    }
}

ToolbarRole was added in SwiftUI 4 and a toolbar role provides a description of the purpose of content that populates the toolbar. The purpose of the content influences how a toolbar renders its content. For example, a browserwill automatically leading align the title of a toolbar in iPadOS.

.navigationTitle("DevTechie.com").toolbarRole(.browser).toolbar

We can also set placement to be primaryAction value, a primary action is a more frequently used action for the current context. For example, a button the user clicks or taps to compose a new message in a chat app. In macOS and in Mac Catalyst apps, the location for the primary action is the leading edge of the toolbar. In iOS, iPadOS, and tvOS, the location for the primary action is the trailing edge of the navigation bar. In watchOS the system places the primary action beneath the navigation bar; the user reveals the action by scrolling.

struct DevTechieToolbarExample: View {
    @State private var counter = 0
    var body: some View {
        NavigationStack {
            VStack {
                Text("Learn iOS Development")
                Text("with")
                Text("DevTechie")
                Text("Count: \(counter)")
                    .font(.largeTitle.bold())
                    .foregroundColor(.white)
                    .padding()
                    .background(.indigo, in: RoundedRectangle(cornerRadius: 20))
                
            }
            .navigationTitle("DevTechie.com")
            .toolbarRole(.browser)
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button {
                        counter += 1
                    } label: {
                        Image(systemName: "plus.circle.fill")
                    }
                }
                ToolbarItem(placement: .automatic) {
                    Button {
                        counter += 1
                    } label: {
                        Image(systemName: "xmark.circle.fill")
                    }
                }
                ToolbarItem(placement: .automatic) {
                    Button {
                        counter -= 1
                    } label: {
                        Image(systemName: "minus.circle.fill")
                    }
                }
            }
        }
    }
}