swiftuitabview

Programmatically changing the TabView focus


I have a SwiftUI TabView that calls 5 separate views: Location, Calculate etc.

enter image description here

These work perfectly. But some views are called programmatically within the App. So, for example, when you have chosen your Location you move to the Calculate view. When I do this how would I programatically tell it to move the TabView focus onto the Calculate icon from the CalculateView?

I have a separate MenuView that controls the Tabs:

struct MenuView: View {
    
    @State public var selectedTab = Tab.location  // was private
    
    public enum Tab: Hashable {
            case location
            case calculate
            case install
            case results
            case about
    }
    
    var body: some View {
        VStack {
            TabView(selection: $selectedTab) {
                LocationView()
                    .tabItem {
                        Label("Location", systemImage: "globe.europe.africa")
                    }
                    .tag(Tab.location)
                CalculateView()
                    .tabItem {
                        Label("Calculate", systemImage: "apps.ipad")
                    }
                    .tag(Tab.calculate)
                InstallView()
                    .tabItem {
                        Label("Install", systemImage: "window.ceiling.closed")
                    }
                    .tag(Tab.install)
                ResultsView()
                    .tabItem {
                        Label("Results", systemImage: "sun.max.fill")
                    }
                    .tag(Tab.results)
                AboutView()
                    .tabItem {
                        Label("About", systemImage: "gear")
                    }
                    .tag(Tab.about)
            } // TabView
            .accentColor(.yellow)                                               //Active tab color
            .background(Color.white)
        }                                                                       // VStack
    }                                                                               // body
    
    init() {
        UITabBar.appearance().barTintColor = UIColor.systemGray //TabBar color
        UITabBar.appearance().backgroundColor = UIColor.white
        UITabBar.appearance().unselectedItemTintColor = UIColor.red //systemGray
        UITabBar.appearance().isOpaque = false
    }
} 

Solution

  • Pass the selectedTab as a binding to the tab views, and in these views, declare @Binding var selectedTab: Tab and change the value in there.

    Here is a working example code, that outlines the approach:

    struct ContentView: View {
        var body: some View {
            MenuView()
        }
    }
    
    struct CalculateView: View {
        @Binding var selectedTab: Tab
        
        var body: some View {
            Button("click me CalculateView", action: {selectedTab = Tab.install} )
        }
    }
    
    struct LocationView: View {
        @Binding var selectedTab: Tab
        
        var body: some View {
            Button("click me LocationView", action: {selectedTab = Tab.calculate} )
        }
    }
    
    struct InstallView: View {
        @Binding var selectedTab: Tab
        
        var body: some View {
            Button("click me InstallView", action: {selectedTab = Tab.location} )
        }
    }
    
    public enum Tab: Hashable {
            case location
            case calculate
            case install
            case results
            case about
    }
    
    struct MenuView: View {
        
        @State var selectedTab = Tab.location
    
        var body: some View {
            VStack {
                TabView(selection: $selectedTab) {
                    LocationView(selectedTab: $selectedTab)  // <-- here
                        .tabItem {
                            Label("Location", systemImage: "globe.europe.africa")
                        }
                        .tag(Tab.location)
                    CalculateView(selectedTab: $selectedTab)
                        .tabItem {
                            Label("Calculate", systemImage: "apps.ipad")
                        }
                        .tag(Tab.calculate)
                    InstallView(selectedTab: $selectedTab)
                        .tabItem {
                            Label("Install", systemImage: "window.ceiling.closed")
                        }
                        .tag(Tab.install)
    //                ResultsView()
    //                    .tabItem {
    //                        Label("Results", systemImage: "sun.max.fill")
    //                    }
    //                    .tag(Tab.results)
    //                AboutView()
    //                    .tabItem {
    //                        Label("About", systemImage: "gear")
    //                    }
    //                    .tag(Tab.about)
                } // TabView
                .accentColor(.yellow)
                .background(Color.white)
            }
        }
        
        init() {
            UITabBar.appearance().barTintColor = UIColor.systemGray //TabBar color
            UITabBar.appearance().backgroundColor = UIColor.white
            UITabBar.appearance().unselectedItemTintColor = UIColor.red //systemGray
            UITabBar.appearance().isOpaque = false
        }
    }