Programmatic Routing in SwiftUI for TabView

94 Views Asked by At

I'm working on a SwiftUI application that follows a navigation pattern similar to Instagram, with a TabView at the root and complex navigation paths starting from different tabs. I've set up my navigation based on a method described in a blog post about creating a better TabView in SwiftUI, but I'm running into issues with more complex navigation flows.

The Problem:

My app has two main navigation flows starting from FeedsView and ProfileView, both of which are part of the TabView. The navigation flow is as follows:

FeedsView -> FeedDetailsView -> EditFeedView
ProfileView -> FeedDetailsView -> EditFeedView

However, when navigating from ProfileView, the navigation to EditFeedView doesn't work as expected. Here's the simplified DetailsView code:

struct DetailsView: View {
    var body: some View {
        VStack {
            Text("Details")
            NavigationLink(value: FeedNavDestination.edit) {
                Text("Open Edit screen")
            }
        }
        .padding()
        .navigationTitle("Details")
        .navigationBarTitleDisplayMode(.inline)
    }
}

FeedNavDestination.edit doesn't trigger navigation when coming from ProfileView.

Here's an overview of my TabView setup:

struct ContentView: View {
    @StateObject var appState = AppState()

    var body: some View {
        
        ScrollViewReader { proxy in
                TabView(selection: createTabViewBinding(scrollViewProxy: proxy)) {
                    FeedView()
                        .tag(ContentViewTab.home)
                        .tabItem {
                            Label("Home", systemImage: "house.fill")
                        }
                    
                    SearchView()
                        .tag(ContentViewTab.settings)
                        .tabItem {
                            Label("Search", systemImage: "magnifyingglass")
                        }
                    
                    ProfileView()
                        .tag(ContentViewTab.profile)
                        .tabItem {
                            Label("Profile", systemImage: "person")
                        }
                    
                    
                }
            
        }
        .environmentObject(appState)
    }
    private func createTabViewBinding(scrollViewProxy: ScrollViewProxy) -> Binding<ContentViewTab> {
            Binding<ContentViewTab>(
                get: { appState.selectedTab },
                set: { selectedTab in
                    if selectedTab == appState.selectedTab {
                        switch selectedTab {
                        case .home:
                            if appState.feedNavigation.isEmpty {
                               
                            } else {
                                withAnimation {
                                    appState.feedNavigation = []
                                }
                            }
                        case .settings:
                            if appState.searchNavigation.isEmpty {
                            
                            } else {
                                withAnimation {
                                    appState.searchNavigation = []
                                }
                            }
                        case .profile:
                            print("profile")
                            
                            
                        }
                    }
                    appState.selectedTab = selectedTab
                }
            )
        }
}

And the navigation model:

class AppState: ObservableObject {
    @Published var selectedTab: ContentViewTab = .home
    
    @Published var feedNavigation: [FeedNavDestination] = []
    @Published var searchNavigation: [SearchNavDestination] = []
    @Published var profileNavigation: [ProfileNavDestination] = []
}

enum AppNavDestination {
    case homeDetails
    case searchDetails
    case edit
    
    // Add other destinations as needed
}

enum ContentViewTab {
    case home
    case profile
    case settings
}

enum FeedNavDestination {
    case details
    case edit
}

enum SearchNavDestination {
    case details
    case edit
}
enum ProfileNavDestination {
    case settings
}

Additional Issue:

Navigating to SearchView from any other tab results in non-functional navigation links because it contains a NavigationStack, similar to the other views. Questions:

  • How can I ensure that navigation to EditFeedView works correctly from both FeedsView and ProfileView?

  • How can I address the issue where navigation stops working when switching tabs that contain their own NavigationStack?

I'm looking for guidance or solutions to these navigation challenges in a SwiftUI app with a structure similar to Instagram's navigation pattern. Any suggestions or insights would be greatly appreciated.

0

There are 0 best solutions below