Tabview Resets Navigation Stack When Switching Tabs

TabView resets navigation stack when switching tabs

Here's a simple example of how to preserve state for a navigation stack with a list of items at the root:

struct ContentView: View {

var body: some View {

TabView {

Text("First tab")
.tabItem { Image(systemName: "1.square.fill"); Text("First") }
.tag(0)

SecondTabView()
.tabItem { Image(systemName: "2.square.fill"); Text("Second") }
.tag(1)
}
}
}

struct SecondTabView: View {

private struct ListItem: Identifiable {
var id = UUID()
let title: String
}

private let items = (1...10).map { ListItem(title: "Item #\($0)") }

@State var selectedItemIndex: Int? = nil

var body: some View {

NavigationView {
List(self.items.indices) { index in
NavigationLink(destination: Text(self.items[index].title),
tag: index,
selection: self.$selectedItemIndex) {
Text(self.items[index].title)
}
}
.navigationBarTitle("Second tab", displayMode: .inline)
}
}
}

Unwind NavigationView to root when switching tabs in SwiftUI

You'll need to keep track of the tab selection in the parent view and then pass that into the child views so that they can watch for changes. Upon seeing a change in the selection, the child view can then reset a @State variable that change the isActive property of the NavigationLink.

class NavigationManager : ObservableObject {
@Published var activeTab = 0
}

struct MyTabView: View {
@StateObject private var navigationManager = NavigationManager()

var body: some View {
TabView(selection: $navigationManager.activeTab) {
TabOne().tabItem { Image(systemName: "1.square") }.tag(0)
TabTwo().tabItem { Image(systemName: "2.square") }.tag(1)
}.environmentObject(navigationManager)
}
}

struct TabOne: View {
var body: some View {
Text("1")
}
}

struct TabTwo: View {
@EnvironmentObject private var navigationManager : NavigationManager
@State private var linkActive = false

var body: some View {
NavigationView {
NavigationLink("Go to sub view", isActive: $linkActive) {
TabTwoSub()
}
}.onChange(of: navigationManager.activeTab) { newValue in
linkActive = false
}
}
}

struct TabTwoSub: View {
var body: some View {
Text("Tapping \(Image(systemName: "1.square")) doesnt unwind this view back to the root of the NavigationView")
.multilineTextAlignment(.center)
}
}

Note: this will result in a "Unbalanced calls to begin/end appearance transitions" message in the console -- in my experience, this is not an error and not something we have to worry about

Reset NagivationView stack in TabView

That's because the View won't be rerendered. Here is a possible approach how to achieve your behavior:

You can use ProxyBinding for the TabView to detect changes and then reset the NavigationLink by changing the internal State variable.

struct ContentView: View {
@State var activeView: Int = 0
@State var showNavigation: Bool = false
var body: some View {
TabView(selection: Binding<Int>(
get: {
activeView
}, set: {
activeView = $0
showNavigation = false //<< when pressing Tab Bar Reset Navigation View
}))
{
NavigationView {
NavigationLink("Click", destination: Text("Page A"), isActive: $showNavigation)
}
.tabItem {
Image(systemName: "1.circle")
Text("First")
}
.tag(0)

Text("Second View")
.padding()
.tabItem {
Image(systemName: "2.circle")
Text("Second")
}
.tag(1)
}
}
}

TabView is not switching tabs properly in SwiftUI

You're binding your TabView's current tab to $selectedTab, but not providing SwiftUI with any information on how to alter that value when the user changes tabs. And so, because selectedTab hasn't changed, when the drawing system comes to review your view structure, it still concludes that you want to see the first tab.

You should add a .tag modifier after each .tabItem to tell SwiftUI what values represent each tab. Then, when the user selects each tab, selectedTab will be updated and the tab choice will "stick".

For example:

TabView(selection: $selectedTab) {
ChatList(launchedChatID: appState.selectedChatID ?? "", userModel: userModel, chatModel: chatModel)
.tabItem {
Image(systemName: "message.circle.fill")
Text("Active Chats")
}
.tag(0)
UserList(userModel: userModel)
.tabItem {
Image(systemName: "person.3.fill")
Text("User List")
}
.tag(1)
ProfileView()
.tabItem {
Image(systemName: "person.crop.circle")
Text("Profile")
}
.tag(2)
}

Note that unless you're persisting the user's choice in some way (e.g., by declaring your state variable with @SceneStorage) you can get the same effect by not using a selection argument at all.

TabView Indicator doesn't move when page changes

The green area below does move to the right, but only 1 pixel. Try something like this example code, choose the value (200) most suited for your purpose:

.onAppear {
self.tabOffset = CGFloat(index*200) // <-- here
}

Tabview not switching tabs properly

Solution:

TabView(selection: $currentIndex) {
ForEach(0..<hvm.upcomingFilms.count) { film in
MediaImageView(mediaPath: hvm.upcomingFilms[film], poster: false)
.scaledToFill()
}
}

TabView keeping state on tab changes SwiftUI

I see what you mean now (I think).
My internet is very fast and so I could not see the ProgressView going on.

You could try this in RickAndMortyViewModel:

@Published var loadingone: Bool = true
@Published var loadingtwo: Bool = true

func getpageone() {
if !loadingone {return}
...
}

func getpagetwo() {
if !loadingtwo {return}
...
}


Related Topics



Leave a reply



Submit