Search code examples
swiftuiuitabbarswiftui-tabview

SwiftUI Custom Tab Bar icons not changing the tab. Area is above it


I am currently having trouble with my Custom Tab Bar there is a gray area above it (Tab View) that controls each tab but I need that to go under my custom tab bar but functionality of the TabView still be in effect and be used with the icons. You can hide the Tab bar with UITabBar.apperance() which gets rid of the gray area but no longer has any functions.. but I need that gray area to go under the tabs. If that makes sense?

Light gray area is the area i need under the icons. Thanks.

Home.swift

import SwiftUI

struct Home: View {
    
    //Hiding Tab Bar..
    init() {
        UITabBar.appearance().isHidden = false
    }
    
    var body: some View {
        
        VStack(spacing: 0){
            //Tab View...
            TabView{
                
                Color.blue
                    .tag("house.circle")
                
                Color.green
                    .tag("pencil")
                
                Color.pink
                    .tag("magnifyingglass")
                
                Color.red
                    .tag("bell")
                
                Color.yellow
                    .tag("cart")
            }

            //Custom Tab Bar...
            CustomTabBar()
        }
        .ignoresSafeArea()
    }
}

struct Home_Previews: PreviewProvider {
    static var previews: some View {
        Home()
    }
}

//Extending View To Get Screen Frame...

extension View {
    func getRect()->CGRect {
        return UIScreen.main.bounds
    }
}

CustomTabBar.swift

import SwiftUI

struct CustomTabBar: View {
    
    var body: some View {
            HStack(spacing: 0){
                
                // Tab Bar Button...
                TabBarButton(systemName: "house.circle")
                    .background(Color.blue)
                
                TabBarButton(systemName: "pencil")
                    .background(Color.green)
                
                Button(action: {}, label: {
                        
                    Image(systemName: "magnifyingglass")
                            .resizable()
                            .renderingMode(.template)
                            .aspectRatio(contentMode: .fit)
                            .frame(width:24, height:24)
                            .foregroundColor(.white)
                            .padding(20)
                            .background(Color.green)
                            .clipShape(Circle())
                        //Shadows
                            .shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
                            .shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
                })
                .tag("magnifyingglass")
                
                TabBarButton(systemName: "bell")
                    .background(Color.red)
                TabBarButton(systemName: "cart")
                    .background(Color.yellow)
            }
            .padding(.top)
            //Decreasing the extra padding added...
            .padding(.vertical, -0)
            .padding(.bottom,getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
            .background(Color.white)
    }
}

struct CustomTabBar_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
        }
    }
}

//extending view to get safe area...
extension View {
    func getSafeArea()-> UIEdgeInsets {
        return UIApplication.shared.windows.first?.safeAreaInsets ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }
}

struct TabBarButton: View {
    
    var systemName: String
    
    var body: some View{
        Button(action: {
        }, label: {
            
            VStack(spacing: 8){
                
                Image(systemName)
                    .resizable()
                    //Since its asset image...
                    .renderingMode(.template)
                    .aspectRatio(contentMode: .fit)
                    .frame(width:28, height: 28)
            }
            .frame(maxWidth: .infinity)
        })
    }
}

EDIT: SECOND IMAGE I am hiding the tab bar setting it to true instead of false.

//Hiding Tab Bar..
    init() {
        UITabBar.appearance().isHidden = true
    }


Solution

  • you could try this to "cover" the original TabView bar:

    In Home replace VStack with ZStack.

    and

    struct CustomTabBar: View {
        
        var body: some View {
            VStack (alignment: .leading) {
                Spacer()
                HStack(spacing: 0) {
                    TabBarButton(systemName: "house.circle").background(Color.blue)
                    TabBarButton(systemName: "pencil").background(Color.green)
                    Button(action: {}, label: {
                        Image(systemName: "magnifyingglass")
                                .resizable()
                                .renderingMode(.template)
                                .aspectRatio(contentMode: .fit)
                                .frame(width:24, height:24)
                                .foregroundColor(.white)
                                .padding(20)
                                .background(Color.green)
                                .clipShape(Circle())
                            //Shadows
                                .shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
                                .shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
                    })
                    .tag("magnifyingglass")
                    
                    TabBarButton(systemName: "bell").background(Color.red)
                    TabBarButton(systemName: "cart").background(Color.yellow)
                }
            }
                .padding(.bottom, getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
                .background(Color.white)
        }
    }
    

    you will then need to implement the action of each of your CustomTabBar buttons.

    EDIT1:

    ok, as I mentioned you need to implement the actions for your buttons. There are many ways to do this, this is just one approach:

    struct CustomTabBar: View {
        @Binding var tagSelect: String
        
        var body: some View {
            VStack (alignment: .leading) {
                Spacer()
                HStack(spacing: 0) {
                    TabBarButton(tagSelect: $tagSelect, systemName: "house.circle").background(Color.blue)
                    TabBarButton(tagSelect: $tagSelect, systemName: "pencil").background(Color.green)
                    Button(action: {}, label: {
                        Image(systemName: "magnifyingglass")
                                .resizable()
                                .renderingMode(.template)
                                .aspectRatio(contentMode: .fit)
                                .frame(width:24, height:24)
                                .foregroundColor(.white)
                                .padding(20)
                                .background(Color.green)
                                .clipShape(Circle())
                            //Shadows
                                .shadow(color: Color.black.opacity(0.05), radius: 5, x: 5, y: 5)
                                .shadow(color: Color.black.opacity(0.05), radius: 5, x: -5, y: -5)
                    })
                    .tag("magnifyingglass")
                    
                    TabBarButton(tagSelect: $tagSelect, systemName: "bell").background(Color.red)
                    TabBarButton(tagSelect: $tagSelect, systemName: "cart").background(Color.yellow)
                }
            }
            .padding(.bottom,getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
            // no background or use opacity, like this
            .background(Color.white.opacity(0.01)) // <-- important
        }
    }
    
    extension View {
        func getSafeArea()-> UIEdgeInsets {
            return UIApplication.shared.windows.first?.safeAreaInsets ?? UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }
    }
    
    struct TabBarButton: View {
        @Binding var tagSelect: String
        var systemName: String
        
        var body: some View{
            Button(action: {tagSelect = systemName }, label: {
                VStack(spacing: 8){
                    Image(systemName)
                        .resizable()
                        .renderingMode(.template)
                        .aspectRatio(contentMode: .fit)
                        .frame(width:28, height: 28)
                }
                .frame(maxWidth: .infinity)
            })
        }
    }
    struct Home: View {
        @State var tagSelect = "house.circle"
    
        init() {
            UITabBar.appearance().isHidden = false
        }
        
        var body: some View {
            ZStack {
                TabView (selection: $tagSelect) {
                    Color.blue.tag("house.circle")
                    Color.green.tag("pencil")
                    Color.pink.tag("magnifyingglass")
                    Color.red.tag("bell")
                    Color.yellow.tag("cart")
                }
                CustomTabBar(tagSelect: $tagSelect)
            }
            .ignoresSafeArea()
        }
    }
    
    extension View {
        func getRect()->CGRect {
            return UIScreen.main.bounds
        }
    }