Search code examples
animationswiftuitabview

SwiftUI: animating tab item addition/removal in tab bar


In my app I add/remove a subview to/from a TabView based on some condition. I'd like to animate tab item addition/removal in tab bar. My experiment (see code below) shows it's not working. I read on the net that TabView support for animation is quite limited and some people rolled their own implementation. But just in case, is it possible to implement it?

import SwiftUI

struct ContentView: View {
    @State var showBoth: Bool = false

    var body: some View {
        TabView {
            Button("Test") {
                withAnimation {
                    showBoth.toggle()
                }
            }
                .tabItem {
                    Label("1", systemImage: "1.circle")
                }

            if showBoth {
                Text("2")
                    .tabItem {
                        Label("2", systemImage: "2.circle")
                    }
                    .transition(.slide)
            }
        }
    }
}

Note: moving transition() call to the Label passed to tabItem() doesn't work either.


Solution

  • As commented Apple wants the TabBar to stay unchanged throughout the App.
    But you can simply implement your own Tabbar with full control:

    struct ContentView: View {
        
        @State private var currentTab = "One"
        @State var showBoth: Bool = false
    
        var body: some View {
            VStack {
                TabView(selection: $currentTab) {
                    // Tab 1.
                    VStack {
                        Button("Toggle 2. Tab") {
                            withAnimation {
                                showBoth.toggle()
                            }
                        }
                    } .tag("One")
                    
                    // Tab 2.
                    VStack {
                        Text("Two")
                    } .tag("Two")
                }
                
                // custom Tabbar buttons
                Divider()
                HStack {
                    OwnTabBarButton("One", imageName: "1.circle")
                    
                    if showBoth {
                    OwnTabBarButton("Two", imageName: "2.circle")
                        .transition(.scale)
                    }
                }
            }
        }
        
        func OwnTabBarButton(_ label: String, imageName: String) -> some View {
            Button {
                currentTab = label
            } label: {
                VStack {
                    Image(systemName: imageName)
                    Text(label)
                }
            }
            .padding([.horizontal,.top])
        }
    }