-
-
Save anivaros/2e291e7d92e2b8cb5463e9e842b752d9 to your computer and use it in GitHub Desktop.
SwiftUI tab bar view that respects navigation stacks when tabs are switched (unlike the TabView implementation)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
/// An iOS style TabView that doesn't reset it's childrens navigation stacks when tabs are switched. | |
struct UIKitTabView: View { | |
var viewControllers: [UIHostingController<AnyView>] | |
@State var selectedIndex: Int = 0 | |
init(_ views: [Tab]) { | |
self.viewControllers = views.map { | |
let host = UIHostingController(rootView: $0.view) | |
host.tabBarItem = $0.barItem | |
return host | |
} | |
} | |
var body: some View { | |
TabBarController(controllers: viewControllers, selectedIndex: $selectedIndex) | |
.edgesIgnoringSafeArea(.all) | |
} | |
struct Tab { | |
var view: AnyView | |
var barItem: UITabBarItem | |
init<V: View>(view: V, barItem: UITabBarItem) { | |
self.view = AnyView(view) | |
self.barItem = barItem | |
} | |
// convenience | |
init<V: View>(view: V, title: String?, image: String? = nil, systemImage: String? = nil, selectedImage: String? = nil) { | |
let image = image != nil ? UIImage(named: image!) : systemImage != nil ? UIImage(systemName: systemImage!) : nil | |
let selectedImage = selectedImage != nil ? UIImage(named: selectedImage!) : nil | |
let barItem = UITabBarItem(title: title, image: image, selectedImage: selectedImage) | |
self.init(view: view, barItem: barItem) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import UIKit | |
struct TabBarController: UIViewControllerRepresentable { | |
var controllers: [UIViewController] | |
@Binding var selectedIndex: Int | |
func makeUIViewController(context: Context) -> UITabBarController { | |
let tabBarController = UITabBarController() | |
tabBarController.viewControllers = controllers | |
tabBarController.delegate = context.coordinator | |
tabBarController.selectedIndex = 0 | |
return tabBarController | |
} | |
func updateUIViewController(_ tabBarController: UITabBarController, context: Context) { | |
tabBarController.selectedIndex = selectedIndex | |
} | |
func makeCoordinator() -> Coordinator { | |
Coordinator(self) | |
} | |
class Coordinator: NSObject, UITabBarControllerDelegate { | |
var parent: TabBarController | |
init(_ tabBarController: TabBarController) { | |
self.parent = tabBarController | |
} | |
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { | |
if parent.selectedIndex == tabBarController.selectedIndex, | |
let selectedView = parent.controllers[tabBarController.selectedIndex].viewIfLoaded, | |
let scrollView = selectedView.subviews(ofType: UIScrollView.self).first, | |
scrollView.scrollsToTop == true { | |
scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.adjustedContentInset.top), animated: true) | |
} else { | |
parent.selectedIndex = tabBarController.selectedIndex | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct ExampleView: View { | |
@State var text: String = "" | |
var body: some View { | |
UIKitTabView([ | |
UIKitTabView.Tab(view: NavView(), title: "First"), | |
UIKitTabView.Tab(view: Text("Second View"), title: "Second", systemImage: "star.fill") | |
]) | |
} | |
} | |
struct NavView: View { | |
var body: some View { | |
NavigationView { | |
VStack { | |
NavigationLink(destination: Text("This page stays when you switch back and forth between tabs (as expected on iOS)")) { | |
Text("Go to detail") | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment