SwiftUI - TabBar Button Change

Viewed 836

Hi I'm learning SwiftUI and I encountered a problem while trying to build an app. My question is how can I make a tab bar that changes a systemImage while active (when the home button is active it shows "home.fill", and when the user presses the search button, the home button changes to "home").

If you see any improvement that I could make in the code below it's appreciated as well. Thank you, have a nice day, and stay safe.

import SwiftUI

struct ContentView: View {
    
    @State private var fullScreenCover = false
    
    init() {
        UITabBar.appearance().isTranslucent = false
    }
    
    var body: some View {
        
        VStack {
            ForEach(0..<6) { num in
                Spacer()
            }
            
            HStack {
                Spacer()
                Button(action: {}, label: {
                    Image(systemName: "message")
                    .font(.system(size: 20))
                })
                .padding(.horizontal, 15)
            }
            .foregroundColor(Color("Reverse"))
            .padding(.vertical, 8)
            
            TabView {
                Main_Home()
                .tabItem {
                    Image(systemName: "house")
                    .font(.system(size: 30))
                }
                
                Main_Search()
                .tabItem {
                    Image(systemName: "magnifyingglass")
                    .font(.system(size: 30))
                }
                
                Main_AddContent()
                .tabItem {
                    Image(systemName: "plus.viewfinder")
                    .font(.system(size: 30))
                }
                
                Main_Message()
                .tabItem {
                    Image(systemName: "pencil.circle.fill")
                    .font(.system(size: 30))
                }
                
                Main_Profile()
                .tabItem {
                    Image(systemName: "person.crop.circle")
                    .font(.system(size: 30))
                }
            }
            .accentColor(Color("Reverse"))
            
        }
        .background(Color("Normal"))
        .edgesIgnoringSafeArea(.all)
    }
}
1 Answers

Here is a custom ViewModifier that you can use for adding tab items:

public struct TabViewItem<SelectionValue>: ViewModifier where SelectionValue: Hashable {
    @Binding private var selectedIndex: SelectionValue
    private let index: SelectionValue
    private let text: String
    private let imageName: String

    public init(selectedIndex: Binding<SelectionValue>, index: SelectionValue, text: String, imageName: String) {
        self._selectedIndex = selectedIndex
        self.index = index
        self.text = text
        self.imageName = imageName
    }

    public func body(content: Content) -> some View {
        content
            .tabItem {
                image
                Text(text)
            }
            .tag(index)
    }

    private var image: some View {
        guard selectedIndex == index else {
            return Image(systemName: imageName)
        }
        let imageName = self.imageName + ".fill"
        if let uiImage = UIImage(systemName: imageName) {
            return Image(uiImage: uiImage)
        }
        return Image(systemName: self.imageName)
    }
}
public extension View {
    func tabItem<Selection>(
        _ text: String,
        imageName: String,
        index: Selection,
        selection: Binding<Selection>
    ) -> some View where Selection: Hashable {
        modifier(TabViewItem(selectedIndex: selection, index: index, text: text, imageName: imageName))
    }
}

Then, creating the TabView is more straightforward:

struct ContentView: View {
    @State private var selectedTab = 3

    var body: some View {
        TabView(selection: $selectedTab) {
            Text("Main_Home")
                .tabItem("Home", imageName: "house", index: 1, selection: $selectedTab)
            Text("Main_Search")
                .tabItem("Search", imageName: "magnifyingglass", index: 2, selection: $selectedTab)
            Text("Main_AddContent")
                .tabItem("AddContent", imageName: "plus.viewfinder", index: 3, selection: $selectedTab)
            Text("Main_Message")
                .tabItem("Message", imageName: "pencil.circle", index: 4, selection: $selectedTab)
            Text("Main_Profile")
                .tabItem("Profile", imageName: "person.crop.circle", index: 5, selection: $selectedTab)
        }
    }
}

Note: The above implementation is for generic purposes - if you don't need some parts (like text in tabs) just remove it or make them optional.

Related