I need to catch UITabBarController item selection for the case when user taps on camera item and app requests permissions and if permissions not granted then not show Camera VC. Is it possible?
Implement
func tabBarController(_ tabBarController: UITabBarController,
shouldSelect viewController: UIViewController) -> Bool {
if viewController is YourVC {
}
else {}
}
And conform to UITabBarControllerDelegate
Related
I have a Swift application with 4 bottom tabs. In the home tab I have a video running. In the 4th tab I have a favorites list.
When the user changes tabs, if he's on the home screen, the video should stop. Also, when the user taps on the 4th tab, the favorites list should update so that the user can see the recent additions.
I have the following on the home tab view controller:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
print("TAB CHANGED")
if let jwp = jwPlayer {
jwp.stop()
}
}
and this on the favorites tab view controller:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
if tabBarIndex == 3 {
let userId = UserDefaults.standard.integer(forKey: "userId")
favoritesVC.updateData(with: userId)
}
}
Both conform to UITabBarControllerDelegate. Both include:
self.tabBarController?.delegate = self
When I launch the app, the video starts playing, I tap on any tab and the video stops. No matter which tab I tap on I see the message "TAB CHANGED". But as soon as I tap on the favorites tab and I move to another, I stop seeing the "TAB CHANGED" message. If I then move to the home screen and play the video and then move to a different tab, the video no longer stops.
The didSelect on the 4th tab is cancelling the didSelect on the 1st tab.
How can I get both of them to work? I have placed them on both view controllers because on the first one I need to reference the video and on the 2nd one I need to reference the list view controller (the 4th view controller actually has two top tabs which switch between a favorites vc and a downloads vc).
UPDATE:
I moved the delegate to the TabBarController subclass. I added the following:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
let hvc = HomeViewController()
if tabBarIndex != 0 {
hvc.stopPlayer()
}
}
I added
delegate = self
and
class TabBarViewController: UITabBarController, UITabBarControllerDelegate {
In the HomeViewController I added this:
func stopPlayer() {
print("TAB CHANGED")
if let jwp = jwPlayer {
jwp.stop()
}
}
however when I change tabs, jwPlayer is always nil.
It seems like you are handling the UITabBarControllerDelegate calbacks in multiple places and for that to happen, you are also changing following multiple times -
self.tabBarController?.delegate = self
Here's what you should do -
Handle UITabBarControllerDelegate in one place.
Dispatch the necessary work calls from there to relevant screens.
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if tabBarIndex == 0 {
homeVC.startPlayer()
}
else {
homeVC.stopPlayer()
if tabBarIndex == 3 {
let userId = UserDefaults.standard.integer(forKey: "userId")
favoritesVC.updateData(with: userId)
}
}
}
This can be handled anywhere, inside your TabBarController subclass if you have one, or any other object that is guaranteed to exist for the application lifetime.
TabBarController’s delegate does not have to be either of the view controllers. It could be some other object (not even a view controller) that could hold weak references to both view controllers, for example, or post a notification etc
I need to display the UITabBarController, but I don't need it to switch me to the Controller from the viewControllers array. Can I reassign the event or would it be better to create my own such TabBarController?
You can create a subclass for UITabBarController and confirm to UITabBarControllerDelegate
Then you can perform custom tab section actions in shouldSelect method.
func tabBarController(_ tabBarController: UITabBarController,
shouldSelect viewController: UIViewController) -> Bool
{
if viewController == secondViewController {
//Do your actions
return false
}
return true
}
Ok, I have looked through https://developer.apple.com/videos/play/wwdc2013/218/ and SO questions similarly trying to make custom transitions with a tab bar controller and its viewcontrollers but Im running into confusion after figuring out the main steps here.
I need to know how (meaning example code would be really helpful) to call a custom UIView.transition OR just have a custom option in UIView.transition. I need to use this to make a sliding/modal -mimicking transition between tabs in my tab bar controller.
The only way I can get a transition to happen is using the below function (this makes them dissolve):
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if selectedViewController == nil || viewController == selectedViewController {
return false
}
let fromView = selectedViewController!.view
let toView = viewController.view
UIView.transition(from: fromView!, to: toView!, duration: 0.3, options: [.transitionCrossDissolve], completion: nil)
return true
}
And calling it manually here where I programmatically chnage the *selectedIndex* for my tab controller:
//SWITCHES BUTTON -------------------------------------------
func switchTab(index: Int)
{
//transition
self.tabBarController(self, shouldSelect: (viewControllers?[index])!)
I have read about and tried making a custom class UIViewControllerAnimatedTransitioning but don't know how this would fit in programmatically here -
my attempts passing my tab bar controller and the toView and fromViewinto the custom class result in nothing happening/animating. That is why Ive resorted to UIView.transition here.
How can I make a custom UIView.transition? What can I do here?
You should conform to UITabBarControllerDelegate
and Create a customTransition class and pass it as follows:
func tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let animator = TabAnimationManager()
return animator
}
And Class TabAnimationManager should be a subclass of UIPercentDrivenInteractiveTransition and conform UIViewControllerAnimatedTransitioning protocol. You can add your custom animations in that class.
I want to know when the tab in the tab bar changes, so that i can report it to Firebase Analytics. How do i do this.
I tried this
override func viewDidAppear(_ animated: Bool) {
Analytics.logEvent("projects_open", parameters: [:])
}
But i have a feeling that what would also run when i go back to it from another ViewController. I need something that can detect when a tab is opened, not when it becomes visible.
Is there another func that works for this?
Swift 3.0
Use this two delegate methods, and don't forget to assign delegate to self.
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
//MARK: - UITabBarControllerDelegate
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
//MARk: - UITabBarDelegate
}
There is a delegate function on UITabbarController for detecting that a tab was selected:
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController)
You can also access the selected index like this:
tabController.selectedIndex
If you use only tabBar.in viewDidLoad set tabBar delegate to self and
override func tabBar(_ tabBar: UITabBar, didSelect item:UITabBarItem)
{
//MARk: - UITabBarDelegate
if(tabBar.selectedIndex == 0) {
//Do something
}
else if(tabBar.selectedIndex == 1) {
//Do something.
}
}
and if you use tabBarController use this method.And mark delegate as self
func tabBarController(_ tabBarController: UITabBarController,
didSelect viewController: UIViewController) {
}
Very important Note:
If you want to save which tabBar was previously selected you have to save it on your way.Either use flag or NSUserDefaults according to your wish. The reason i mentioned this because i needed to check which tab has been selected right now in View in one of my project.
Swift 5
Easy way just click on link StakOverFlow screen will open
https://stackoverflow.com/a/60539396/6881070
Normally when a UINavigationController is placed in a UITabBarController the navigation controller pops to root with the respective tab it is in is double tapped. How do I achieve the same effect with a UISplitViewController is between the tab bar controller and the navigation controller? Ideally it would recurse through the view controller's child view controllers and calling popToRootViewController on all navigation controllers that it finds. Do I have to add my own gesture recognizer to the tab bar since it doesn't look like there is a hook for knowing when a user has double tapped a tab?
In Swift 4, it can go something like this:
class TabBarViewController: UITabBarController, UITabBarControllerDelegate {
private var shouldSelectIndex = -1
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
shouldSelectIndex = tabBarController.selectedIndex
return true
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if shouldSelectIndex == tabBarController.selectedIndex {
if let splitViewController = viewController as? UISplitViewController {
if let navController = splitViewController.viewControllers[0] as? UINavigationController {
navController.popToRootViewController(animated: true)
}
}
}
}
}
Instead of setting up a UIGestureRecognizer I simply keep track of the selected index in shouldSelectViewController and popped to root on my master navigation controller in didSelectViewController if the old selected index was the same as the new one.