Reputation: 1181
I tried to switch to another tab(say, WorkOutView()) when pressing a button on SocialView(). However, I've been using a wrapped struct of UIKit tabview in SwiftUI.
The Wrapper:
struct UIKitStyleTabView: View {
var viewControllers: [HostingController<AnyView>]
//@State var switchTab = 0
struct Tab {
var view: AnyView
var barItem: UITabBarItem
init<V: View>(view: V, barItem: UITabBarItem) {
self.view = AnyView(view)
self.barItem = barItem
}
}
init(_ tabs: [Tab]) {
self.viewControllers = tabs.map {
let host = HostingController(rootView: $0.view)
host.tabBarItem = $0.barItem
return host
}
}
var body: some View {
TabBarController(controllers: viewControllers, switchTab: $switchTab)
.edgesIgnoringSafeArea(.all)
}
}
struct TabBarController: UIViewControllerRepresentable {
var controllers: [UIViewController]
@Binding var switchTav: Int
func makeUIViewController(context: Context) -> UITabBarController {
let tabBarController = UITabBarController()
tabBarController.viewControllers = controllers
return tabBarController
}
func updateUIViewController(_ uiViewController: UITabBarController, context: Context) {
//uiViewController.selectedIndex = switchTab
}
}
And I set up like this:
struct MainView : View {
//@Binding var switchTab: Int
let tabBarSymbolConfig = UIImage.SymbolConfiguration(scale: .medium)
var body : some View {
UIKitStyleTabView([
UIKitStyleTabView.Tab(view: SocialView(switchTab: $switchTab).accentColor(.white), barItem: UITabBarItem(title: "Social", image: UIImage(systemName: "person.3.fill", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: SearchView().accentColor(.white), barItem: UITabBarItem(title: "Search", image: UIImage(systemName: "magnifyingglass", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: WorkoutsView().accentColor(.white),barItem: UITabBarItem(title: "Workouts", image: UIImage(systemName: "doc.on.clipboard.fill", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: ExercisesView().accentColor(.white), barItem: UITabBarItem(title: "Exercises", image: UIImage(systemName: "sportscourt", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: AccountView().accentColor(.white), barItem: UITabBarItem(title: "Me", image: UIImage(systemName: "person.crop.circle", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
)
], switchTab: $switchTab).accentColor(.navIconColor)
I tried to insert a state/binding variable everywhere connecting these views, so that I can use it in the function updateUIViewController, but that didn't really work out, because I ended up having to insert a Binding into SceneDelegate.
Any suggestions how to achieve this?
Upvotes: 1
Views: 1400
Reputation: 258491
Here is corrected & worked variant (replicated due to many absent components it is, so adapting back is on you).
Tested with Xcode 11.4 / iOS 13.4
Full module code:
struct UIKitStyleTabView: View {
var viewControllers: [UIHostingController<AnyView>]
@Binding var switchTab: Int
struct Tab {
var view: AnyView
var barItem: UITabBarItem
init<V: View>(view: V, barItem: UITabBarItem) {
self.view = AnyView(view)
self.barItem = barItem
}
}
init(_ tabs: [Tab], switchTab: Binding<Int>) {
self.viewControllers = tabs.map {
let host = UIHostingController(rootView: $0.view)
host.tabBarItem = $0.barItem
return host
}
self._switchTab = switchTab
}
var body: some View {
TabBarController(controllers: viewControllers, switchTab: $switchTab)
.edgesIgnoringSafeArea(.all)
}
}
struct TabBarController: UIViewControllerRepresentable {
var controllers: [UIViewController]
@Binding var switchTab: Int
func makeUIViewController(context: Context) -> UITabBarController {
let tabBarController = UITabBarController()
tabBarController.viewControllers = controllers
tabBarController.delegate = context.coordinator
return tabBarController
}
func updateUIViewController(_ uiViewController: UITabBarController, context: Context) {
uiViewController.selectedIndex = switchTab
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITabBarControllerDelegate {
let owner: TabBarController
init(_ owner: TabBarController) {
self.owner = owner
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
owner.switchTab = tabBarController.selectedIndex
}
}
}
struct TabsMainView : View {
@State var switchTab: Int = 0
let tabBarSymbolConfig = UIImage.SymbolConfiguration(scale: .medium)
var body : some View {
UIKitStyleTabView([
UIKitStyleTabView.Tab(view: SocialView(switchTab: $switchTab).accentColor(.white), barItem: UITabBarItem(title: "Social", image: UIImage(systemName: "person.3.fill", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: Text("SearchView").accentColor(.white), barItem: UITabBarItem(title: "Search", image: UIImage(systemName: "magnifyingglass", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: Text("WorkoutsView").accentColor(.white),barItem: UITabBarItem(title: "Workouts", image: UIImage(systemName: "doc.on.clipboard.fill", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: Text("ExercisesView").accentColor(.white), barItem: UITabBarItem(title: "Exercises", image: UIImage(systemName: "sportscourt", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
), UIKitStyleTabView.Tab(view: Text("AccountView").accentColor(.white), barItem: UITabBarItem(title: "Me", image: UIImage(systemName: "person.crop.circle", withConfiguration: tabBarSymbolConfig)!.withBaselineOffset(fromBottom: 4.5), selectedImage: nil)
)
], switchTab: $switchTab)//.accentColor(.navIconColor)
}
}
struct SocialView: View {
@Binding var switchTab: Int
var body: some View {
Button("Go Search") { self.switchTab = 1 }
}
}
struct TabsMainView_Previews: PreviewProvider {
static var previews: some View {
TabsMainView().colorScheme(.dark)
}
}
Upvotes: 1