swiftui-router icon indicating copy to clipboard operation
swiftui-router copied to clipboard

Switch between flows

Open IlyasNN opened this issue 2 years ago • 2 comments

Please provide information or example how to switch between different flows in case when one of the flow contains TabView.

So I have registration flow and main flow with tab bar (I use original swiftUI TabView with TabContents)

And I can't find approach how I can navigate to tabView after registration flow is completed. I get empty TabView. I suppose that's because tabView is a set of routes(views inside) and if I use tabView as root view it's okey. But if I use some empty root view as router that navigates to registration or tabView flow it can't navigate correctly to tabView

IlyasNN avatar Sep 21 '22 12:09 IlyasNN

The quickest I can do now is link you to the TabView example which uses a TabView with SwiftUI Router. It uses a TabView at the top level of the view hierarchy, though the logic for a TabView inside a router shouldn't be too different. 🙂

frzi avatar Sep 21 '22 15:09 frzi

I have seen this example. TabView is used as a root view here... I want to create something like these:

IMG_5572 If I add TabView as second screen after empty root view for routing, I get empty tabView... Any ideas how to solve the issue?

IlyasNN avatar Sep 22 '22 10:09 IlyasNN

Finally had a chance to give this a try. So far I experienced no problems getting the TabView to behave nicely.

Here's the entire contents for the ContentView. The only thing omitted here is the Router, which is wrapped around the ContentView in the App (inside the WindowGroup). This was tested on iOS 16.

import SwiftUI
import SwiftUIRouter

extension String: Identifiable {
	public var id: Self { self }
}

enum Constants {
	static let titles: [(title: String, image: String)] = [
		("Movies", "film"),
		("Music", "music.note"),
		("Books", "book"),
	]
}

struct ContentView: View {
	var body: some View {
		SwitchRoutes {
			Route("tabs/*") {
				TabsView()
			}

			Route {
				VStack {
					ForEach(Array(Constants.titles.enumerated()), id: \.element.title) { (index, element) in
						NavLink(to: "/tabs/" + element.title) {
							Text("Go to /tabs/" + element.title)
						}
					}
				}
			}
		}
	}
}

private struct TabsView: View {
	@EnvironmentObject private var navigator: Navigator
	@EnvironmentObject private var routeInformation: RouteInformation
	@State private var selected = -1

	private func setTabForRoute(_ route: String) {
		if let index = Constants.titles.firstIndex(where: { $0.title == route }) {
			selected = index
		}
	}

	var body: some View {
		TabView(selection: $selected) {
			ForEach(Array(Constants.titles.enumerated()), id: \.element.title) { (index, element) in
				VStack {
					Text(element.title)
					NavLink(to: "/") {
						Text("Back to root")
					}
				}
				.tag(index)
				.tabItem {
					Label(element.title, systemImage: element.image)
				}
			}
		}
		.onChange(of: selected) { newIndex in
			navigator.navigate(routeInformation.path + "/" + Constants.titles[newIndex].title)
		}
		.onChange(of: navigator.path) { newPath in
			let components = newPath.components(separatedBy: "/").dropFirst()
			if let route = components.first {
				setTabForRoute(route)
			}
		}
		.onAppear {
			let components = navigator.path[routeInformation.path.endIndex...].components(separatedBy: "/").dropFirst()
			if let route = components.first {
				setTabForRoute(route)
			}
		}
	}
}

The code was written hasty. Plenty of room for cleaning up 🙂

frzi avatar Oct 01 '22 12:10 frzi