Custom back button for navigation bar in SwiftUI
In this tutorial, we will see how to create a custom back button and implement a custom action for the navigation bar in SwiftUI.
When we are using an iPhone app, there is a little Back button in the top left corner that takes us to the previous screen. We can customize that back button and also its action but this will be not a straightforward way. Apple makes it a bit tricky if we want to do something special when someone presses that button.
This is because Apple wants to maintain consistent navigation view behavior across its entire app ecosystem.
Custom back button and action in SwiftUI
If we want a custom back button and action, we need to do two things which are mentioned below.
- Hide the default back button
- Create own custom back button.
Now, I will explore the above two approaches to achieve this task.
Hide the default back button
First of all, we have to hide the default back button that SwiftUI provides when we navigate to another view. We can achieve this by using the navigationBarBackButtonHidden()
modifier and specifying the boolean value true
as an argument within this modifier.
Syntex:
.navigationBarBackButtonHidden(true)
Simply, we have to apply the above modifier to the view for which we want to hide the back button.
Example
struct DetailView: View { var body: some View { Text("Detail View") .navigationBarBackButtonHidden(true) } }
In the above program, I have hidden the navigation back button for the DetailView
using the .navigationBarBackButtonHidden(true)
modifier.
So, when we navigate to the DetailView
there will be no back button in that view.
Output:
As you can see in the above output, the navigation back button has been removed.
Create own custom back button.
After hiding the default back button, We can create our own button to act as the back button. We can do this using the toolbar
modifier along with ToolbarItem(placement: .navigationBarLeading)
to position the button on the leading edge of the navigation bar.
Within the ToolbarItem
I will create a button with a label and a back button symbol using the SF Symbol. I will use HStack
to align the button and the symbol horizontally.
Example
struct DetailView: View { var body: some View { Text("Detail View") // Hide the default back button in the navigation bar .navigationBarBackButtonHidden(true) // Define custom toolbar items for the navigation bar .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { // Action to be performed when the custom back button is tapped print("Button Pressed") } label: { // Creating a button with an image and text HStack { Image(systemName: "chevron.backward") // Back chevron icon Text("Custom Button") // Text label for the back button } } } } } }
In the above program, I have used toolbar
modifier along with the ToolbarItem
to customize the navigation bar of our DetailView
by adding a custom button with a specific placement and action.
Then, Within the ToolbarItem
, I have created a button with the label “Custom Button” and an icon of a back chevron (<
).
I have added the ToolbarItem
with a placement of .navigationBarLeading
, to place the button on the leading side of the navigation bar.
So, when we navigate to the DetailView
it will display the text “Detail View” in the center of the screen, and a custom back button (“Custom button“) to the leading side of the navigation bar.
Now, have a look at the complete code below.
import SwiftUI // The view where we want to navigate struct DetailView: View { var body: some View { Text("Detail View") // Hide the default back button in the navigation bar .navigationBarBackButtonHidden(true) // Define custom toolbar items for the navigation bar .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { // Action to be performed when the custom back button is tapped print("Button Pressed") } label: { // Creating a button with an image and text HStack { Image(systemName: "chevron.backward") // Back chevron icon Text("Custom Button") // Text label for the back button } } } } } } // The main view, from where we want to navigate struct ContentView: View { var body: some View { NavigationView { // Navigate to the DetailView when this link is tapped NavigationLink("Detail") { DetailView() } // Set the title of the navigation bar in the ContentView .navigationTitle("Home") } } }
The ContentView
is the main view of our SwiftUI app. It contains a NavigationView
with a NavigationLink
labeled “Detail“, when we tap the link it will navigate us to the DetailView
.
Whenever we tap the custom back button (“Custom Button“) of the DetailView
, it will print “Button Pressed” each time to the console.
Output:
Dismiss the View
When we hide the default back button in SwiftUI, it removes the built-in functionality for navigating back.
So, if we add our own custom back button, it won’t automatically handle going back as the default one does. Also, swiping from the leading edge to go back won’t work anymore.
Here, we can use either the DismissAction
for iOS 15 or PresentationMode
for iOS 13-14, to dismiss the view.
iOS 15: Using DismissAction
In iOS 15 and later versions, we can utilize the DismissAction
environment value to dismiss the view.
Example
struct DetailView: View { // Create an environment variable to access the dismiss action @Environment(\.dismiss) private var dismiss var body: some View { Text("Detail View") .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { // Call the dismiss action to dismiss the current view dismiss() } label: { HStack { Image(systemName: "chevron.backward") Text("Custom Button") } } } } } }
In the above program, I have declared the @Environment(\.dismiss)
to access the dismissal functionality, and then I have called the dismiss()
within the button action to dismiss the view.
Output:
iOS 13-14: Using PresentationMode
For versions earlier than iOS 15, we can use PresentationMode
environment value.
Example
struct DetailView: View { // Access the presentation mode environment variable to control navigation @Environment(\.presentationMode) var presentationMode var body: some View { Text("Detail View") .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { // Custom button action to dismiss the current view presentationMode.wrappedValue.dismiss() } label: { HStack { Image(systemName: "chevron.backward") Text("Custom Button") } } } } } }
In the above program, I have declared @Environment(\.presentationMode)
and called presentationMode.wrappedValue.dismiss()
within the button action to dismiss the view.
Output:
Leave a Reply