Home Leveraging ToolbarContentBuilder to Refactor Your SwiftUI Toolbar Code
Post
Cancel

Leveraging ToolbarContentBuilder to Refactor Your SwiftUI Toolbar Code

Just like SwiftUI’s ViewBuilder, ToolbarContentBuilder is used to put together dynamic ui content for toolbars

Intro

In SwiftUI, the Toolbar component is essential for adding UI elements like buttons, menus, and controls to the navigation bar or bottom bar of our app. However, as our apps grows and becomes more complex, the toolbar code can become cluttered and difficult to manage. This is where ToolbarContentBuilder comes to the rescue. The ToolbarContentBuilder attribute provides us with a clean way to refactor our toolbar code and keep it organized. The goal of this article is for us to explore how to use ToolbarContentBuilder to streamline our toolbar logic implementations, but first let’s take a look at the problem.

The Challenge with Complex Toolbars

As our SwiftUI app evolves, we might find yourself needing to add multiple buttons, menus, or other UI elements to the toolbar. Without proper organization, the toolbar code can quickly become hard to read, maintain, and extend. This is especially true when we are dealing with conditional or dynamic toolbar content.

Consider the following scenario: we have a view that needs to display different toolbar buttons depending on the user’s authentication status. In traditional SwiftUI code, we might end up with something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var body: some View {
    NavigationStack {
        VStack {

        }
            .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                if isAuthenticated {
                    Button("Profile") {
                        // Show user profile
                    }
                }
            }
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("Settings") {
                    // Show app settings
                }
            }
        }
    }
}

As you can see, the code becomes cluttered with conditional statements and nested blocks. Additionally, if we need to add more toolbar items or refactor existing ones, the code can become even more convoluted. And if you’re like me, who likes to prioritize a streamlined view’s body for improved readability, this clearly presents a noteworthy concern.

Introducing ToolbarContentBuilder

The ToolbarContentBuilder is a declarative way to build our toolbar content in SwiftUI. It simplifies the process of creating complex toolbars by allowing us to refactor our toolbarItems into functions or computed properties just by simply annotating them with the @ToolbarContentBuilder attribute. Think of it as viewbuilder for composing dynamic content views for our toolbars.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   @ToolbarContentBuilder
    private var cancelToolbarButton: some ToolbarContent {
        ToolbarItem(placement: .navigationBarLeading) {
            Button("Cancel") {
                // canceling...
            }
        }
    }
    
    @ToolbarContentBuilder
    private var downloadToolbarButton: some ToolbarContent {
        ToolbarItem(placement: .navigationBarTrailing) {
            Button("Download") {
                // downloading...
            }
        }
    }
    
    @ToolbarContentBuilder
    private var dismissKeyboardToolbarButton: some ToolbarContent {
        ToolbarItem(placement: .keyboard) {
            Button("Dismiss") {
                // dismissing keyboard here
            }
        }
    }

Now inside of our toolbar modifier, we can easily compose the toolbar content like this:

1
2
3
4
5
6
7
8
9
10
11
12
var body: some View {
    NavigationStack {
        VStack {

        }
        .toolbar {
           cancelToolbarButton
           downloadToolbarButton
           dismissKeyboardToolbarButton
        }
    }
}

Bye

Hopefully you found some value in this neat little toolbar refactoring approach, thanks for reading.

This post is licensed under CC BY 4.0 by the author.