Dynamic TabView in SwiftUI

1 minute read

I am working on an upcoming project that helps a developer visualize many elements on the screen with SF symbols. I started off with the idea of creating dynamic tab views but didn’t find much on the internet. Although, I stumbled upon a discussion that gave me the head-start to develop it. Here’s a small article to summarise my learnings.

The discussion can be found here — SOLVED: How do I append a new page into TabView, PageTabViewStyle?

Model

I start off by creating a TabItem with a unique identifier, name, image, and tag associated with it.

struct TabItem: Identifiable {
    let id = UUID()
    let name: String
    let image: String
    let tag: Int
}

ViewModel

Then, I create a class conforming to ObservableObject that will house our tab items, with methods to add or remove them.

final class DynamicTabViewModel: ObservableObject {
    @Published var tabItems: [TabItem] = []
    @Published var tabCount = 1

    func addTabItem() {
        tabItems.append(TabItem(name: " Tab \(tabCount)", image: "0\(tabCount).square", tag: tabCount))
          tabCount += 1
        }

    func removeTabItem() {
        tabItems.removeLast()
        tabCount -= 1
    }
}

View

I create a View with a state object of DynamicTabViewModel. I add a TabView that loops over the tabItems and shows them inside a label. There are two navigation buttons to add or remove the tab items. Every time those methods are called, the view reloads with the new set of tab items.

struct DynamicTabView: View {
    @StateObject private var viewModel = DynamicTabViewModel()

    var body: some View {
        NavigationView {
            TabView {
                ForEach(viewModel.tabItems) { item in
                    Text(item.name)
                        .font(.largeTitle)
                        .tabItem {
                            Label(item.name, systemImage: item.image)
                        }
                        .tag(item.tag)
                }
            }
            .navigationTitle("Dynamic Tab View")
            .navigationBarItems(leading: Button(action: viewModel.addTabItem) {
                Text("Add")
            }, trailing: Button(action: viewModel.removeTabItem) {
                Text("Remove")
            })
        }
    }
}

Screen with dynamic tab items

Conclusion

Although this was a simple example, this gave me a solid foundation to add more customizable features to my app.

You may use this functionality to create a backend-driven tab view. The data for the number of tab items and their information can be parsed from JSON, and then the published variable is updated accordingly. Do note that it is discouraged in Human Interface Guidelines to “remove or disable a tab when its function is unavailable.”