TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

`TabView` with `tabViewStyle(.page)` not behaving as expected when app loads.

Forums > SwiftUI

I've been experimenting with TabView and tabViewStyle and I've run into a problem with my code I can't figure out.

In the code below, when the app opens up on my device I start on the HomeScreen() (as expected) but if I tap on Profile in the top bar, the tab navigation doesn't happen. The Profile text turns red (indicating that pageIndex has been updated), but for reasons I can't figure out, the TabView isn't updating accordingly.

BUT, if I open the app and tap on Settings in the top bar, the tab navigation happens as expected.

Swiping works as expected, no issues there.

Have I missed something obvious?

I've tested in canvas, simulator and - most importantly - on device... and it's all the same.

import SwiftUI

struct SwipeNavigation2: View {
    @State var pageIndex = 1

    var body: some View {
        NavigationView {
            TabView(selection: self.$pageIndex) {
                // The screen to the "left" of the Home screen
                ProfileScreen()
                    .tag(0)

                // The screen we want the app to load on
                HomeScreen()
                    .tag(1)

                // The screen to the "right" of the Home screen
                SettingsScreen()
                    .tag(2)
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
            .navigationTitle("")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                        withAnimation(.spring()) {
                            pageIndex = 0
                        }
                    } label: {
                        Text("Profile")
                            .foregroundColor(pageIndex == 0 ? .red : .primary)
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        withAnimation(.spring()) {
                            pageIndex = 2
                        }
                    } label: {
                        Text("Settings")
                            .foregroundColor(pageIndex == 2 ? .red : .primary)
                    }
                }
            }
        }
    }
}

private struct ProfileScreen: View {
    var body: some View {
        Text("Profile screen")
    }
}

private struct HomeScreen: View {
    var body: some View {
        Text("Home screen")
    }
}

private struct SettingsScreen: View {
    var body: some View {
        Text("Settings screen")
    }
}

Some additional information: I tried setting pageIndex to 0 and using .onAppear to set it to 1, but the behaviour remains broken.

2      

I have put your code in a new project and it works fine!

Even add extra ToolBarItem for Home

ToolbarItem(placement: .principal) {
    Button {
        withAnimation(.spring()) {
            pageIndex = 1
        }
    } label: {
        Label("Home", systemImage: "house")
            .font(.title)
            .foregroundColor(pageIndex == 1 ? .red : .primary)
    }
}

2      

@NigelGee Could you give me some more details about how you tested?

So far, I've tried the following, all without success (this seems to be pretty comprehensive to me):

  • Canvas (doesn't work)
  • Simulator, iPhone 14 (doesn't work)
  • On my physical device, plugged into my machine (iPhone 13 mini)

XCode 14.1

2      

I just pasted you code into a new Xcode project. Used the simulator and preview and worked fine. Xcode 14.2

2      

So just to be clear, when you say it worked fine: when you opened the app and tapped on Profile first (without tapping or swiping) and the page animated to the profile page? Or did the profile button just turn red?

2      

Managed to make it work by initializing the tab with 0 then on appear to change tabIndex with the passed value

struct ExamplePage: View {
    var tabIndex = 0
    @State var tab = 0
    var body: some View {

                TabView(selection: $tab) {
                    Text("1")
                        .tag(0)
                    Text("2")
                        .tag(1)
                    Text("3")
                        .tag(2)
                }
                .onAppear(perform: {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                        if tabIndex != tab {
                            tab = tabIndex
                        }
                    }

                }

        }
}

2      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.