'There doesn't appear to be support for UITabBar in SwiftUI. Workarounds?

SwiftUI doesn't appear to support UITabBar. How can I integrate that capability?

Merely wrapping the view like one would a (eg) MKMapView, doesn't work because of its need for deep integration with NavigationView. Using UINavigationView is too un-SwiftUI-ish.



Solution 1:[1]

The 'TabbedView' is the closest thing. It can be used similar to the following:

    struct TabView : View {

        @State private var selection = 1

        var body: some View {
            TabbedView (selection: $selection) {
                InboxList()
                    .tabItemLabel(selection == 1 ? Image("second") : Image("first"))
                    .tag(1)

                PostsList()
                    .tabItemLabel(Image("first"))
                    .tag(2)

                Spacer()
                    .tabItemLabel(Image("first"))
                    .tag(3)

                Spacer()
                    .tabItemLabel(Image("second"))
                    .tag(4)
            }
        }
    }

Solution 2:[2]

If you aren't happy with TabbedView, you can always roll your own! Here's a quick base implementation:

import SwiftUI

struct ContentView : View {

    let tabs = [TabItemView(title: "Home", content: { Text("Home page text") }), TabItemView(title: "Other", content: { Text("Other page text") }), TabItemView(title: "Pictures", content: { Text("Pictures page text") })]

    var body: some View {
        TabBar(tabs: tabs, selectedTab: tabs[0])
    }
}

struct TabItemView<Content> : Identifiable where Content : View {
    var id = UUID()
    var title: String
    var content: Content

    init(title: String, content: () -> Content) {
        self.title = title
        self.content = content()
    }


    var body: _View { content }

    typealias Body = Never
}

struct TabBar<Content>: View where Content : View {
    let tabButtonHeight: Length = 60

    var tabs: [TabItemView<Content>]
    @State var selectedTab: TabItemView<Content>

    var body: some View {
        GeometryReader { geometry in
        VStack(spacing: 0) {
            self.selectedTab.content.frame(width: geometry.size.width, height: geometry.size.height - self.tabButtonHeight)

            Divider()
            HStack(spacing: 0) {
                    ForEach(self.tabs) { tab in
                        Button(action: { self.selectedTab = tab}) {
                            Text(tab.title)
                        }.frame(width: geometry.size.width / CGFloat(Double(self.tabs.count)), height: self.tabButtonHeight)

                    }
                }
                .background(Color.gray.opacity(0.4))
            }
            .frame(width: geometry.size.width, height: geometry.size.height)

        }
    }
}

Solution 3:[3]

UITabBar seems to be working now on Xcode 13.3, SwiftUI 3, iOS15+ It works even though I didn't import UIKit, not sure if that has any effect but it's working for me

    struct LandingView: View {
    @Binding var selectedTab: String
    
    //hiding tab bar
    init(selectedTab: Binding<String>) {
        self._selectedTab = selectedTab
        UITabBar.appearance().isHidden = true 
    }
    
    var body: some View {
        //Tab view with tabs
        TabView(selection: $selectedTab) {
            //Views
            Home() 
                .tag("Home")
            PlaylistView()
                .tag("My Playlists")
            HistoryView()
                .tag("History")
            
        }
    }
}

Solution 4:[4]

I misstated the question as I was trying to make ToolBar... below is the code I ended up with... thanks to all.

struct ToolBarItem : Identifiable {
    var id = UUID()
    var title : String
    var imageName : String
    var action: () -> Void
}

struct TooledView<Content> : View where Content : View{
    var content :  Content
    var items : [ToolBarItem]
    let divider = Color.black.opacity(0.2)

    init(items : [ToolBarItem], content: () -> Content){
        self.items = items
        self.content = content()
    }
    var body : some View{
        VStack(spacing: 0){
            self.content
            self.divider.frame(height: 1)
            ToolBar(items: self.items).frame(height: ToolBar.Height)
        }
    }
}

struct ToolBar : View{
    static let Height : Length = 60
    var items : [ToolBarItem]
    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 0){
                ForEach(self.items){ item in
                    Button(action: item.action){
                        Image(systemName: item.imageName).imageScale(.large)
                        Text(item.title).font(.caption)
                    }.frame(width: geometry.size.width / CGFloat(Double(self.items.count)))

                }

            }
                .frame(height: ToolBar.Height)
                .background(Color.gray.opacity(0.10))
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 piebie
Solution 2 piebie
Solution 3 Simbarashe
Solution 4 Rumbles