Disabling taskbar after changing ViewController in Swift? - ios

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
}

Related

DidSelect TabBar Item Not Being Called

So I have a UITabBarController with two View Controllers Embedded into it. I implemented the did select tab bar method where when the user selects a tab, it passes a value into that controller. However when the tabBarController loads for the first time, the did select method is not called even though I have
self.selectedIndex = 0
Which selects the first index. Basically I am just trying to automatically select the first tab Bar Item when the view loads, and have it call the didSelectTabBarItem method
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
}
The question is similar to this one.
tabBarController didSelect does not get called
optional func tabBarController(_ tabBarController: UITabBarController,
didSelect viewController: UIViewController)
In iOS v3.0 and later, the tab bar controller calls this method regardless of whether the selected view controller changed. In addition, it is called only in response to user taps in the tab bar and is not called when your code changes the tab bar contents programmatically.
Copy this in your code
class HomeTabBarVC: UITabBarController {
var isIpad = false
let button = UIButton.init(type: .custom)
var index = 0
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
APPDELEGATE.tabBar = self
}
}
extension HomeTabBarVC : UITabBarControllerDelegate {
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print("the last selected index is : \(selectedIndex)")
APPDELEGATE.tabBarLastSelectedIndex = selectedIndex
print("the current selected index is : \(String(describing: tabBar.items?.index(of: item)))")
APPDELEGATE.tabBarCurrentSelectedIndex = tabBar.items?.index(of: item) ?? 0
}
}
In appdelegate declare this variable,
var tabBar : UITabBarController?

Prevent a tabBar moving to the next View Controller onselect

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
}

iOS on tab bar change

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

Dismiss View Controller inside UITabController

I've a project which contains a tab controller, as the main 'page'.
I want to add a UITabBar button item, which presents a view controller modaly, and within that view controller, add a dismiss button that dismisses that view controller and returns to the previous tab selection.
To clarify, it's something that the Medium app for iOS uses, when you click on the create post item, it presents it modaly and dismisses it when you want to.
I can present the view controller, but I can't dismiss it.
Hope I made myself understandable.
Example:
So I've managed to solve this as I wanted to, hope the answer will help someone in the future.
First of all, I set on my first loaded view controller, lets say my 'Home' view controller the tabBarController delegate to be my AppDelegate.swift file (this is personal preference), as:
self.tabBarController?.delegate = UIApplication.shared.delegate as? UITabBarControllerDelegate
Then in my AppDelegate.swift file i added to the class properties the delegate UITabBarControllerDelegate so I could access the tabBarController delegate functions, such as
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {}
Then edited the function to interact with my specific view controller.
The final version of the function:
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController is ViewControllerToPresentModaly {
if let newVC = tabBarController.storyboard?.instantiateViewController(withIdentifier: "modalVC") {
tabBarController.present(newVC, animated: true)
return false
}
}
return true
}
Here if you want the regular tab behaviour, return true or your own return false
;)

An alternative to "Storyboard Reference" for iOS 8 when handling Relationship Segue?

My App has a TabBarViewController containing 4 tabs. One of the tabs is Settings which I want to move to a separate storyboard. If I am only consider iOS 9 and above as my deployment target, then I can just refactor the SettingsTab using Storyboard Reference. However I want to target iOS 8 as well. Since Storyboard Reference doesn't support Relationship Segue, I can't rely on it in this case.
So in the main storyboard which contains the TabBarViewController, I keep a dummy SettingsTabViewController as an empty placeholder. And in the function "viewWillAppear" in its class file, I push the view to the real SettingsTabViewController in the Settings.storyboard. This works fine. But the problem is if I keep tabbing the Settings tab, the empty placeholder view controller will show up for a short time and then goes back to the real Settings view.
I tried to implement this delegate to lock the Settings tab:
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
return viewController != tabBarController.selectedViewController
}
However, the other three tabs were locked too after I implemented this delegate.
Is it possible to just lock the Settings tab without locking other three tabs? And in which view controller exactly should I implement this delegate?
Yes, it's possible. You need to check the index;
with the following code not only you can prevent locking other tabs, but also you still have tap on tab goto root view controller feature.
func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool {
let tappedTabIndex = viewControllers?.indexOf(viewController)
let settingsTabIndex = 3 //change the index
if tappedTabIndex == settingsTabIndex && selectedIndex == settingsTabIndex {
guard let navVC = viewController as? UINavigationController else { return true }
guard navVC.viewControllers.count > 1 else { return true }
let firstRealVC = navVC.viewControllers[1]
navVC.popToViewController(firstRealVC, animated: true)
return false
}
return true
}
.
This answers your question, but still you would have the settingsVC showing up for a moment. To avoid this you simply need to turn off the animation while you're pushing it. so you need to override viewWillAppear in the following way.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let theVC = storyboard?.instantiateViewControllerWithIdentifier("theVC") {
navigationController?.pushViewController(theVC, animated: false)
}
}
after adding above code you still would see a back button in your real first viewController. You can hide it:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.hidesBackButton = true
}

Resources