Prevent a tabBar moving to the next View Controller onselect - ios

I have an item on my tabBar which I don't want to actually move to its view controller but instead when that item is clicked something happens (a popup dialog appears over the current view controller).
I currently have the current code:
class TabViewController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// tell our UITabBarController subclass to handle its own delegate methods
self.delegate = self
}
// called whenever a tab button is tapped
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if viewController is PostTabViewController {
... code here ...
}
}
}
The code at ..code here... runs just fine however the PostTabViewController is still shown. How would I go about stopping it?

You should do your checks in tabBarController(_, shouldSelect:)
func tabBarController(UITabBarController, shouldSelect: UIViewController) -> Bool {
guard viewController is PostTabViewController else {
return true
}
... code here ...
return false
}

Related

getting current active viewController in UITabBarControllerDelegate

I want to implement a scrollToTop method on all of my viewControllers in my UITabBarController. The following is a method in the UITabBarControllerDelegate and triggers, when I select a tab.
The problem is, that I only want to scroll to the top of the viewController, when the viewController is active. So that the user can switch tabs without losing the scroll position, but when he touches the tab in the tabBar of the currently active tab, it should scroll to the top.
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if viewControllerThatIsCurrentlyActiveInTabBar == viewController {
scrollToTop()
}
}
Basically, I need that condition of the if statement above.
I tried: viewController.isViewLoaded, tabBarController.selectedViewController == viewController, viewController.isBeingPresented. None of those conditions worked. It would either not trigger scrollToTop() or it would trigger always so that you lose the scroll position when you change tabs because it would immediately scroll to the top.
You need to make a code in should select instead of didselect. As it is unable to find the previous controller after selection. below is the example code for it.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if tabBarController.selectedViewController == viewController {
print("Same viewcontroller")
}
return true
}
Can you use below extension for getting top viewcontroller of tabbarcontroller.
extension UIViewController {
var top: UIViewController? {
if let controller = self as? UINavigationController {
return controller.topViewController?.top
}
if let controller = self as? UISplitViewController {
return controller.viewControllers.last?.top
}
if let controller = self as? UITabBarController {
return controller.selectedViewController?.top
}
if let controller = presentedViewController {
return controller.top
}
return self
}
}
You can use above extension below
if let rootViewController = UIApplication.top() {
//do with Active view controller
}

Disabling taskbar after changing ViewController in Swift?

I would like to disable the task bar after changing the ViewController programmatically. I have a hover button. After a click on it this code is called to change the ViewController:
self.navigationController?.setViewControllers([lvc!], animated: true)
This works well. After the change I am calling the viewDidLoad method which is also called (checked the console).
The code is like this:
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.tabBar.isUserInteractionEnabled = false
}
The button is in the HomeView. If I am calling self.tabBarController?.tabBar.isUserInteractionEnabled = false
in the viewDidLoad method of the HomeView the tab bar is disabled. I am using NavigationController for presenting the different Views.
Any idea why the tab bar is not disabled and how to fix it?
Try this:
_ = tabBarController?.tabBar.items?.compactMap { $0.isEnabled = false }
You should use the delegate method shouldSelectViewController of the UITabbarControllerDelegate. This delegate asks if the user can select the view controller, in simple words.
See the Apple documentation link
Use it like this:
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
If homeControllerIsDoingSomething {
return false
}
return true
}

Launching segue from tab bar controller

I want to launch segue from tab bar item. When user touches an item on the tab bar. I want to launch a segue.
To do this I writed this code:
class TabBarController: UITabBarController, UITabBarControllerDelegate {
#IBOutlet var tabs: UITabBar!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
if item.tag == 3 {
self.performSegueWithIdentifier("test123", sender: self)
}
}
}
Actually it works well except a problem. This is launching segue but also switching the tab. I don't want this. It should just launch start segue shouldn't switch the tab.
How can I prevent this problem?
Here's the minimal changes to get your code work
in your viewDidLoad() add
self.delegate = self
Then implement delegate method
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
let shouldSelectIndex = tabBarController.viewControllers?.indexOf(viewController)
if shouldSelectIndex == 2
{
self.performSegueWithIdentifier("test123", sender: self)
return false
}
return true
}
That should work.
However I think you have design issues.
Subclass as a delegate is strange. Better separate delegate.
Instead of tag/indecies use introspection or another delegation or something

Swift: How to execute an action when UITabBarItem is pressed

Currently I have a Tab Bar Controller that is connected to a tableview controller. I'm trying to go to the top of the tableview when I press the tab bar item. I know how to get to the top of the tableview. I just don't know how to do an action when the item is pressed.
You should use UITabBarDelegate with method didSelectItem. Use it as any standard delegate:
class yourclass: UIViewController, UITabBarDelegate {
func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
//This method will be called when user changes tab.
}
}
And do not forget to set your tab bar delegate to self in view controller.
Here is an answer to this question
Basically you do this:
Make sure your view controller is subscribed to the UITabBarDelegate
Set tags in IB for each tab bar item
Implement the didSelectItem method, something like this:
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
if(item.tag == 1) {
// Code for item 1
}
else if(item.tag == 2) {
// Code for item 2
}
}
This will give you access to each tab item tapped event. Hope it helps!
In Swift:
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if(item.tag == 1) {
// Code for item 1
} else if(item.tag == 2) {
// Code for item 2
}
}
SWIFT 3
class yourclass: UIViewController, UITabBarDelegate {
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print("Test")
}
}
And do not forget to set your tabBar delegate to self in viewDidLoad
override func viewDidLoad(){
super.viewDidLoad()
<YOUR TAB BAR NAME>.delegate = self
}
I was having trouble implementing the other answers here. This is a fuller answer. It assumes you are using a UITabBarController (the default if you create a new Tabbed App). This solution will print a message every time a view controller tab button is tapped.
Code
Create a new Swift file called MyTabBarController.swift. Paste in the following code.
import UIKit
class MyTabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// tell our UITabBarController subclass to handle its own delegate methods
self.delegate = self
}
// called whenever a tab button is tapped
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if viewController is FirstViewController {
print("First tab")
} else if viewController is SecondViewController {
print("Second tab")
}
}
}
Interface Builder
On your storyboard select the Tab Bar Controller. Then in the Identity inspector, set the class name to MyTabBarController (that is, the name of the class in the code above).
That's all. You can run your app now and be notified whenever the user taps a tab bar item.
Notes
If you need to run a method on a tap, then you can do something like the following in didSelect method.
if let firstVC = viewController as? FirstViewController {
firstVC.doSomeAction()
}
You could do make the FirstViewController implement the delegate and handle everything there. That way you wouldn't need to make any custom UITabBarController subclass and set it in IB. However, having a child do the parent's work seems like the wrong place to do it. Anyway, here is is:
class FirstViewController: UIViewController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
tabBarController?.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
// ...
}
}
The didSelect method above gets called no matter which tab is tapped.
UITabBarControllerDelegate documentation
An alternate solution is to just do something in viewDidAppear in whichever View Controller the tab shows.
First Tab View Controller
import UIKit
class FirstViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("First tab")
}
}
Second Tab View Controller
import UIKit
class SecondViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("Second tab")
}
}
class TestViewController: UIViewController,UITabBarDelegate {
#IBOutlet weak var tabbar: UITabBar!
override func viewDidLoad() {
super.viewDidLoad()
tabbar.delegate = self
}
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print(tabBar.items![1]) // The number is tab index
}
}

How do I call something in my UIViewController in the code of my UITabBarViewController?

I want to call a method on a ViewController (type "MatchesViewController", which is on the 3rd tab of my TabBarViewControlleer) if the selected item is NOT of that class.
This is my delegate function for listening when a Tab Bar Item was changed.
override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem!) {
}
Inside this code, I'd like to detect if the item selected (and its View Controller) is of type "MatchesViewController". If it is NOT of this type, then call method on that controller.
Why not use tabBarController(_:didSelectViewController:) ?
override func tabBarController(tabBarController: UITabBarController,
didSelectViewController viewController: UIViewController)
{
if !(viewController is MatchesViewController) {
let matchesVC = tabBarController.viewControllers?[2] as MatchesViewController
matchesVC.refresh()
}
}

Resources