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?
Steps to reproduce:
Profile
(don't swipe or tap anything else)Profile
will turn red, but the page won't be animated left to the Profile
screen.Settings
or swipe any direction, tapping Profile
will work as expected.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")
}
}
Edit:
I've taken some of the suggestions and amended the code as such:
struct SwipeNavigation2: View {
@State var pageIndex = 0
var body: some View {
NavigationView {
TabView(selection: self.$pageIndex) {
ProfileScreen()
.tag(0)
HomeScreen()
.tag(1)
SettingsScreen()
.tag(2)
}
.onAppear {
pageIndex = 1
}
.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)
}
}
}
}
}
}
Edit 1:
Here's a recording from my simulator (Xcode14.1), on an iPhone 14. You'll see once the recording starts, I tap on Profile
(which turns it red), but the TabView
isn't moving me to the correct page.
https://i.sstatic.net/2uJ0c.jpg
Edit 2:
It gets weirder. I've tested the following devices in XCode simulator:
Move the onAppear
modifier on the tab with the index set at init (in your case the Profile View.
import SwiftUI
struct AdamView: View {
@State var pageIndex: Int = 0
var body: some View {
NavigationView {
TabView(selection: self.$pageIndex) {
Text("Profile")
.onAppear {
pageIndex = 1
}
.tag(0)
Text("Home")
.tag(1)
Text("Settings")
.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)
}
}
}
}
}
}
Another solution is to use the task
modifier instead. With the task, you can keep the onAppear on the TabView but I noticed we see the Profile View for a very short time before showing the Home tab.