I am using UITabBarController in SwiftUI 2.0 and Xcode 12 but seems like Keyboard cases some unexpected behavior. As you can see from the below GIF, OnAppear of the other 2 tab's view called when the keyboard appears in the first tab. That is causing the issue as I have an API call written on appear.
Also, is there any way I can turn off the default view offset behavior of Xcode 12.
Here is my code of Content View.
struct ContentView: View {
@State private var index:Int = 0
var menuItems:[String] = ["Item 1", "Item 2", "Item 3"]
var body: some View {
NavigationView(content: {
ZStack{
MyTabView(selectedIndex: self.$index)
.view(item: self.item1) {
NewView(title: "Hello1").navigationBarTitle("")
.navigationBarHidden(true)
}
.view(item: self.item2) {
NewView(title: "Hello2").navigationBarTitle("")
.navigationBarHidden(true)
}
.view(item: self.item3) {
NewView(title: "Hello3").navigationBarTitle("")
.navigationBarHidden(true)
}
}.navigationBarHidden(true)
.navigationBarTitle("")
})
}
var item1:MyTabItem {
var item = MyTabItem()
item.imageName = "pencil.circle"
item.selectedImageName = "pencil.circle.fill"
return item
}
var item2:MyTabItem {
var item = MyTabItem()
item.imageName = "pencil.circle"
item.selectedImageName = "pencil.circle.fill"
return item
}
var item3:MyTabItem {
var item = MyTabItem()
item.imageName = "pencil.circle"
item.selectedImageName = "pencil.circle.fill"
return item
}
}
struct NewView:View {
@State var text:String = ""
var title:String
var body: some View {
VStack {
Spacer()
Text("Hello")
TextField(title, text: self.$text)
.textFieldStyle(RoundedBorderTextFieldStyle())
}.padding()
.onAppear {
debugPrint("OnApper \(self.title)")
}
}
}
and here is the code for CustomTabView.
class MyTabViewViewModel:ObservableObject {
var controllers: [UIViewController] = []
var tabItems:[MyTabItem] = []
}
struct MyTabItem {
var imageName:String = ""
var selectedImageName:String = ""
var hasDarkModeSupport:Bool = true
var image:UIImage?
var selectedImage:UIImage?
}
struct MyTabView: UIViewControllerRepresentable {
var viewModel:MyTabViewViewModel = MyTabViewViewModel()
@Binding var selectedIndex: Int
func makeUIViewController(context: Context) -> UITabBarController {
let tabBarController = UITabBarController()
tabBarController.viewControllers = self.viewModel.controllers
tabBarController.delegate = context.coordinator
tabBarController.selectedIndex = 0
let appearance = tabBarController.tabBar.standardAppearance
appearance.shadowImage = nil
appearance.shadowColor = nil
appearance.backgroundEffect = nil
tabBarController.tabBar.standardAppearance = appearance
tabBarController.tabBar.shadowImage = UIImage()
tabBarController.tabBar.backgroundImage = UIImage()
tabBarController.tabBar.layer.shadowPath = UIBezierPath(rect: tabBarController.tabBar.bounds).cgPath
tabBarController.tabBar.layer.shadowOffset = CGSize.init(width: 0, height: -3)
tabBarController.tabBar.layer.shadowRadius = 5
tabBarController.tabBar.layer.shadowColor = UIColor.black.cgColor
tabBarController.tabBar.layer.shadowOpacity = 0.25
tabBarController.tabBar.backgroundColor = UIColor.white
tabBarController.tabBar.barTintColor = UIColor.white
self.updateTabItems(forTabBarController: tabBarController)
return tabBarController
}
func updateUIViewController(_ tabBarController: UITabBarController, context: Context) {
tabBarController.selectedIndex = selectedIndex
self.updateTabItems(forTabBarController: tabBarController)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func updateTabItems(forTabBarController tabBarController:UITabBarController) {
let isDarkModeEnable:Bool = tabBarController.traitCollection.userInterfaceStyle == .dark
for (index, tabItem) in self.viewModel.tabItems.enumerated() {
tabBarController.tabBar.items?[index].title = ""
if let image = tabItem.image {
tabBarController.tabBar.items?[index].image = image
if let selectedImage = tabItem.selectedImage {
tabBarController.tabBar.items?[index].selectedImage = selectedImage
}
} else {
if tabItem.hasDarkModeSupport && isDarkModeEnable {
if let image = UIImage.init(systemName: "\(tabItem.imageName)-dark") {
tabBarController.tabBar.items?[index].image = image
} else if let image = UIImage.init(systemName: tabItem.imageName) {
tabBarController.tabBar.items?[index].image = image
}
if let selectedImage = UIImage.init(systemName: "\(tabItem.selectedImageName)-dark") {
tabBarController.tabBar.items?[index].selectedImage = selectedImage
} else if let selectedImage = UIImage.init(systemName: tabItem.selectedImageName) {
tabBarController.tabBar.items?[index].selectedImage = selectedImage
}
} else {
if let image = UIImage.init(systemName: tabItem.imageName) {
tabBarController.tabBar.items?[index].image = image
}
if let selectedImage = UIImage.init(systemName: tabItem.selectedImageName) {
tabBarController.tabBar.items?[index].selectedImage = selectedImage
}
}
}
}
}
class Coordinator: NSObject, UITabBarControllerDelegate {
var parent: MyTabView
init(_ tabBarController: MyTabView) {
self.parent = tabBarController
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
parent.selectedIndex = tabBarController.selectedIndex
}
}
func view<HostedView:View>(item:MyTabItem, @ViewBuilder sheet: @escaping () -> HostedView) -> MyTabView {
self.viewModel.controllers.append(UIHostingController.init(rootView: sheet()))
self.viewModel.tabItems.append(item)
return self
}
}