animationswiftuiviewnavigationtabview

How to make Navigation between views smoothly in SwiftUI


Code: with this code i am navigating to views between(ProfileView(), HomeNew, NotificationsTabView, MessageTabView) very sharp i mean something like very fast change but i need it could be more smoothly change from one view to other

because of my code if i quickly change views one by one then slightly before view dummy data design for a sec showing in current view..

so i need very smooth navigation between views. so how to achieve smooth navigation between views. plz guide me.

struct TabContainerViewNew: View {
    @Binding var index: Int?
    @State private var showSideMenu = false
    @State private var gotoSearch = false

    init(index: Binding<Int?>) {
        self._index = index
        UITabBar.appearance().isHidden = true
    }

    let tabs = [("Menu", "Menu_New"), ("My profile", "user"), ("Home", "MenuNew_Home"), ("Notification", "MenuNew_Notification"), ("Message", "MenuNew_Message")]
    
    var body: some View {
        ZStack(alignment: .bottom) {
            if let index = index {
                TabView(selection: Binding(
                    get: { index },
                    set: { newValue in
                        self.index = newValue
                    }
                )) {
                    ProfileView()
                        .tabItem {
                            Label("My profile", image: "icn_settings_tab")
                        }
                        .tag(1)

                    HomeNew()
                        .tabItem {
                            Label("Home", image: "icn_home_tab")
                        }
                        .tag(2)

                    NotificationsTabView()
                        .tabItem {
                            Label("Notification", image: "icn_notifications_tab")
                        }
                        .tag(3)

                    MessageTabView()
                        .tabItem {
                            Label("Message", image: "icn_message_tab")
                        }
                        .tag(4)
                }
                .tint(.white)
                .transition(.slide)
          }

            VStack(spacing: 0) {
          
                HStack(spacing: 0) {
                    ForEach(0..<tabs.count) { i in
                        if tabs[i].0 == "Menu" {
                            VStack {
                                Button(action: {
                                    withAnimation {
                                        showSideMenu.toggle()
                                    }
                                }) {
                                    Image(tabs[i].1)
                                        .renderingMode(.template)
                                        .resizable()
                                        .scaledToFit()
                                        .tint(.white.opacity(0.6))
                                        .frame(width: 24, height: 24)
                                        .padding(8)
                                }
                                Text(tabs[i].0)
                                    .foregroundColor(.white.opacity(0.6))
                                    .font(.system(size: 11))
                            }
                            .frame(maxWidth: .infinity)
                        } else {
                            TabButton(image: tabs[i].1, title: tabs[i].0, item: i, index: $index)
                                .frame(maxWidth: .infinity)
                        }
                    }
                }
                .padding(.horizontal, 7)
                .padding(.bottom, 15)
                .padding(.top, 5)
                .background(Color.appGreen2)
            }
        }
        
        .sideMenu(isShowing: $showSideMenu) {
            SideMenuView(isShowingMenu: $showSideMenu)
        }
    }
}

struct TabButton: View {
    var image: String
    var title: String
    var item: Int
    @Binding var index: Int?

    var body: some View {
        VStack {
            Button(action: {
                    index = item
            }) {
                Image(image)
                    .renderingMode(.template)
                    .resizable()
                    .foregroundColor(index == item ? .white : .white.opacity(0.6))
                    .frame(width: 24, height: 24)
                    .padding(8)
            }
            Text(title)
                .foregroundColor(index == item ? .white : .white.opacity(0.6))
                .fontWeight(index == item ? .bold : .regular)
                .font(.system(size: (index == item ? 11 : 11)))
        }
        .frame(maxWidth: .infinity) 
    }
}

Solution

  • I was asking for an MRE and didn't get one, but I think there may be a simple solution here.

    Since you are already using a custom tab bar, try using .page as the .tabViewStyle. This provides a slide transition between views:

    TabView( //...
    ) {
        // ...
    }
    .tint(.white)
    // .transition(.slide) // not needed
    .tabViewStyle(.page(indexDisplayMode: .never))
    .animation(.easeInOut, value: index)
    

    That's about the only animation you get with a TabView. If you're after an .opacity transition, or any other kind of transition for that matter, then you'll need to implement the change of view yourself. This is actually not very difficult, especially since you're already using a custom tab bar.

    One way is to replace the TabView with a ZStack and a switch statement:

    ZStack(alignment: .bottom) {
        ZStack {
            switch(index) {
            case 1:
                ProfileView()
            case 3:
                NotificationsTabView()
            case 4:
                MessageTabView()
            default:
                HomeNew()
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .tint(.white)
        .animation(.easeInOut, value: index)
    
        VStack(spacing: 0) {
            // ...
        }
    }