dxalxmur.com

Creating Custom Tab Bars in SwiftUI: A Comprehensive Guide

Written on

Chapter 1: Introduction to Tab Bars in SwiftUI

In the realm of mobile applications, one of the most common features is the tab bar located at the bottom of the screen. This component allows users to effortlessly navigate between various key sections of an app. SwiftUI simplifies the process of creating a tab bar UI with the TabView component.

This tutorial will guide you through the steps of creating and customizing a tab bar, and it's part of my ongoing SwiftUI Tutorial series. Before diving in, please ensure that you have a new project open for practice. If you need a step-by-step guide on starting a new project, follow this link.

Section 1.1: Creating a Basic TabView

To initiate a basic TabView with a single tab, make the following adjustments to the ContentView:

struct ContentView: View {

var body: some View {

TabView {

Text("Home view")

.tabItem {

Image(systemName: "house.fill")

}

} // TabView

} // body

} // ContentView

This code snippet will display a simple tab in the canvas, as shown in Figure 2. Here, all views are encapsulated within the TabView. The .tabItem modifier designates what type of button will be represented in the tab bar. In this case, we've utilized a system image for our tab button.

However, a single tab item renders the tab bar ineffective. Let's enhance it by adding multiple tab items, which we can achieve by modifying the ContentView as follows:

struct ContentView: View {

var body: some View {

TabView {

Text("Home view")

.tabItem {

Image(systemName: "house.fill")

}

Text("Search view")

.tabItem {

Image(systemName: "magnifyingglass")

}

Text("Photo view")

.tabItem {

Image(systemName: "photo.fill")

}

Text("Message view")

.tabItem {

Image(systemName: "envelope.fill")

}

Text("Profile view")

.tabItem {

Image(systemName: "person.crop.circle.fill")

}

} // TabView

} // body

} // ContentView

After executing the application, you can switch between different tabs to see how the views adapt accordingly to their respective tab items. To improve user experience, we can add labels to each tab item. Adjust the ContentView code as follows:

struct ContentView: View {

var body: some View {

TabView {

Text("Home view")

.tabItem {

Image(systemName: "house.fill")

Text("Home")

}

Text("Search view")

.tabItem {

Image(systemName: "magnifyingglass")

Text("Search")

}

Text("Photo view")

.tabItem {

Image(systemName: "photo.fill")

Text("Photos")

}

Text("Message view")

.tabItem {

Image(systemName: "envelope.fill")

Text("Messages")

}

Text("Profile view")

.tabItem {

Image(systemName: "person.crop.circle.fill")

Text("Profile")

}

} // TabView

} // body

} // ContentView

This adjustment will present an enhanced layout with labels, as illustrated in Figure 4.

Section 1.2: Structuring Views for Each Tab

In a practical application, each tab typically comprises multiple views. To follow best practices, it's advisable to create a separate struct for each tab. Here's how to code a basic HomeView:

struct HomeView: View {

var body: some View {

List(1...50, id: .self) {

Text("Content ($0)")

}

} // body

} // HomeView

This example provides a simple ForEach List view mimicking a typical home page for a content-driven app.

Next, let's create a separate view for the "Photos" tab:

struct PhotosView: View {

private var imageList = [

"hare.fill",

"tortoise.fill",

"pawprint.fill",

"ant.fill",

"ladybug.fill"

]

var body: some View {

ScrollView(showsIndicators: false) {

ForEach(imageList, id: .self) { index in

Image(systemName: "(index)")

.font(.system(size: 150))

.padding()

}

}

} // body

} // PhotosView

Now that we have our separate structs, let's modify the ContentView to use these new views for the Home and Photos tabs:

struct ContentView: View {

var body: some View {

TabView {

HomeView()

.tabItem {

Image(systemName: "house.fill")

Text("Home")

}

Text("Search view")

.tabItem {

Image(systemName: "magnifyingglass")

Text("Search")

}

PhotosView()

.tabItem {

Image(systemName: "photo.fill")

Text("Photos")

}

Text("Message view")

.tabItem {

Image(systemName: "envelope.fill")

Text("Messages")

}

Text("Profile view")

.tabItem {

Image(systemName: "person.crop.circle.fill")

Text("Profile")

}

} // TabView

} // body

} // ContentView

After running the application again, you can navigate between tabs, especially testing the Home and Photos views.

Section 1.3: Customizing the Tab Bar Appearance

By default, the active tab item appears blue. If you prefer a different color, you can customize it as follows:

TabView {

// Code

}

.accentColor(.black)

Currently, SwiftUI does not provide a direct modifier for changing the tab bar color. To customize it, you can access UIKit's UITabBar.appearance within the init() function of your ContentView:

init() {

UITabBar.appearance().barTintColor = UIColor.systemBlue

}

To change the color of unselected tabs to white:

UITabBar.appearance().unselectedItemTintColor = UIColor.white

To ensure the tab bar isn't transparent, set it to opaque:

UITabBar.appearance().isOpaque = false

Combining all customization code will give you a tailored UI, as demonstrated in Figure 6.

Section 1.4: Programmatically Switching Tabs

While the tab view automatically switches based on the selected tab item, you can also implement a button outside the tab bar to achieve similar functionality. For instance, create a button that directs the user from the profile view to the message view.

First, let's code the ProfileView:

struct ProfileView: View {

var selection: () -> Void

var body: some View {

VStack {

Image(systemName: "person.crop.circle")

.font(.system(size: 100))

.padding()

Button(action: selection) {

Image(systemName: "envelope.fill")

.font(.system(size: 50))

}

.padding()

} // VStack

} // body

} // ProfileView

Next, in ContentView, introduce a state variable to track the selected tab:

@State private var selection = 0

Then, modify the TabView to bind the selection variable:

TabView(selection: $selection) {

HomeView()

.tabItem {

Image(systemName: "house.fill")

Text("Home")

}

.tag(0)

Text("Search view")

.tabItem {

Image(systemName: "magnifyingglass")

Text("Search")

}

.tag(1)

PhotosView()

.tabItem {

Image(systemName: "photo.fill")

Text("Photos")

}

.tag(2)

Text("Message view")

.tabItem {

Image(systemName: "envelope.fill")

Text("Messages")

}

.tag(3)

ProfileView(selection: {

selection = (selection + 4) % 5

})

.tabItem {

Image(systemName: "person.crop.circle.fill")

Text("Profile")

}

.tag(4)

} // TabView

The action in the ProfileView will trigger the tab switch. The expression (selection + 4) % 5 allows you to cycle through the tab items accurately.

Run the application and press the button in the Profile view; it should seamlessly switch to the Message view.

For the complete source code of this project, you can find it on GitHub. Just click on this link.

May the code be with you,

  • Arc

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Unlocking Mobility: 3 Walking Exercises to Alleviate Joint Pain

Discover three effective walking exercises designed to relieve hip and knee discomfort while enhancing your overall mobility.

Strategies for Cultivating Habits That Lead to Success

Discover effective techniques for establishing habits that drive success in all areas of life.

Navigating Autism: Medication, Education, and Advocacy

Explore the challenges faced by families navigating autism in education, including medication discussions and teacher interactions.

Engaging Generation Z: Authentic Writing Strategies for 2024

Explore effective writing strategies to connect with Generation Z by focusing on authenticity and understanding their unique communication style.

Unmasking the Deceptive Tactics of Self-Help Gurus

Explore the manipulative tactics of self-help gurus and learn to discern their misleading promises in your personal growth journey.

Understanding the Difference Between a Business and a Job

Explore the key principles of Profit First and how to distinguish between owning a business and having a job.

Navigating Uncertainty: Strategies for Job Security Amidst Economic Woes

Explore strategies to prepare for job uncertainty in a fluctuating economy, including insights on funding challenges and personal contingency plans.

Embracing Forgiveness: The Freedom in Letting Go of Debt

Discover the power of forgiveness in financial relationships and learn how letting go can lead to personal peace.