Reset ViewController when tab bar icon is clicked - swift

I have 3 items in my tab bar, each linked to a separate viewController, and I want them to reset each time I switch between any of these items.
How can I do this?

You can create a subclass for your tab bar controller and perform required actions in it.
class TabBarViewController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let viewController0: UIViewController? = tabBarController.viewControllers?[0] as? UIViewController
let viewController1: UIViewController? = tabBarController.viewControllers?[1] as? UIViewController
let viewController2: UIViewController? = tabBarController.viewControllers?[2] as? UIViewController
switch self.selectedIndex {
case 0:
// Refresh viewController1
// Refresh viewController2
case 1:
// Refresh viewController2
// Refresh viewController3
case 2:
// Refresh viewController0
// Refresh viewController1
default:
break
}
}
}

Related

UITabBar item did select is not calling in swift 5

I have used tabbar in swift 5 . But when i click in tabbar item, tabbar didselect item not calling.But I did not used TabbarViewController. I have used bellow code in my viewController..
class ViewController: UIViewController,UITabBarDelegate {
#IBOutlet weak var bottomTab: UITabBar!
override func viewDidLoad() {
super.viewDidLoad()
bottomTab.delegate = self
}
func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
print("Selected item")
}
}
Please help me to calling didSelectItem from viewController
1) In your ViewController inherit UITabBarControllerDelegate
2) Set delegate in a viewDidLoad
3) Add a function
Example:
class ViewController: UIViewController, UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
let tabBarIndex = tabBarController.selectedIndex
if tabBarIndex == 0 {
//do your stuff
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
}
}
I believe you are implementing the incorrect method. Try implementing this method instead:
func tabBar(UITabBar, didSelect: UITabBarItem)
Sent to the delegate when the user selects a tab bar item.
Source

TabBar Controller with custom action

I am new to swift. I am implementing tabbar controller in my Project and facing some design difficulty. My goal is when user click a tabbar item it should not navigate to another view controller. It should stayed in the current view and add a pop up view to the current view controller.I have tried but always it navigate to next view controller.
Create a UITabBarController subclass and use that class for your tab bar controller. Confirm to UITabBarControllerDelegate in the tab bar controller and return false in tabBarController shouldSelect method when you don't want to navigate to a view controller. Here you can show the popup view.
class TabbarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let navigationController = viewController as? UINavigationController,
navigationController.viewControllers.contains(where: { $0 is MoreViewController }) {
//show pop up view
return false
} else {
return true
}
}
}
Or you can add UITabBarControllerDelegate in one of its embedded view controller like this
class ViewController: UIViewController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let navigationController = viewController as? UINavigationController,
navigationController.viewControllers.contains(where: { $0 is MoreViewController }) {
//show pop up view
return false
} else {
return true
}
}
}

Find which tab bar item is selected

I'm looking for a way to find which tab bar item is select on my tab bar controller.
I've got 5 items and for one of them, I would like to show a "registration view" if the user is not logged in.
I've got all my verifications but I don't find the good way to check if the user tapped the fourth item on my tab bar.
Any ideas ? Thanks
self.tabBarController?.delegate = UIApplication.shared.delegate as? UITabBarControllerDelegate
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController is CalculatorViewController {
print("Redirect to register view")
}
return true
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
guard let index = tabBarController.viewControllers?.firstIndex(where: {$0 === viewController}) else {
return false
}
if index == 3 && !IS_LOGGED_IN{
/*** show registration ***/
return false //if you want to disable transition to the associated viewController against that tab
}
return true
}
You can try to use such thing (if you are using navigation controller, for sure)
override func viewDidLoad() {
super.viewDidLoad()
if let index = self.tabBarController?.selectedIndex, index == 3 {
// do things here
}
}
UPD.
Or even like so
override func viewDidLoad() {
super.viewDidLoad()
if !userLogedIn {
self.tabBarController?.selectedIndex = index // index is your tab bar item with login view
}
}

How add tabs programmatically in UITabBarController with swift?

How to create programmatically tabs from any class extended by UIViewController:
class DashboardTabBarController: UITabBarController {
override func viewDidLoad() {
//here
}
...
}
UPDATE SWIFT 5
One example of how to create an UITabBarController programmatically could be like this:
First we create the UIViewControllers that will be the content for each tab of the tab bar interface. For this example we only create one very simple.
class Item1ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.green
self.title = "item1"
print("item 1 loaded")
}
}
Now, the UITabBarController:
We create the new instances of the UIViewControllers that we want to display in the tab bar. Then we create an icon for each instance we have created and then we create an array that contains all UIViewControllers that specify the content for each tab of the tab bar interface. The order of the view controllers in the array corresponds to the display order in the tab bar.
class DashboardTabBarController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let item1 = Item1ViewController()
let icon1 = UITabBarItem(title: "Title", image: UIImage(named: "someImage.png"), selectedImage: UIImage(named: "otherImage.png"))
item1.tabBarItem = icon1
let controllers = [item1] //array of the root view controllers displayed by the tab bar interface
self.viewControllers = controllers
}
//Delegate methods
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
print("Should select viewController: \(viewController.title ?? "") ?")
return true;
}
}
If you are using storyboard for the viewcontrollers then you have to write like this in your tabbarcontroller class.
class CustomTabbarController : UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let firstViewController = FirstViewController()
let navigationController = UINavigationController(rootViewController: firstViewController)
navigationController.title = "First"
navigationController.tabBarItem.image = UIImage.init(named: "map-icon-1")
viewControllers = [navigationController]
if let secondViewController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController {
let navgitaionController1 = UINavigationController(rootViewController: secondViewController)
navgitaionController1.title = "Second"
navgitaionController1.tabBarItem.image = UIImage.init(named: "second-icon-1")
var array = self.viewControllers
array?.append(navgitaionController1)
self.viewControllers = array
}
}
}
private lazy var tabbarViewController: UITabBarController = {
let tabbarViewController = UITabBarController()
tabbarViewController.setViewControllers([startVC,
offerVC,
benefitsVC,
shopVC,
recipesVC], animated: true)
return tabbarViewController
}()
window?.rootViewController = tabbarViewController

Pop to root view when tab is selected

I've been having some trouble with something I thought might be easy. I have a table in my root view controller, when a row is selected I push a new view and from there I go to another tab.
My question is how do I make sure that as soon as the user taps the first tab the navigation controller will pop to root?
Following delegate is called while each tab is selected on tabbar.
-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
Put following code inside this delegate method.
if ([viewController isKindOfClass:[UINavigationController class]])
{
[(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
}
its working fine on my app.
For Swift lovers:
import UIKit
class YourTabBarControllerHere: UITabBarController,
UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self;
}
func tabBarController(tabBarController: UITabBarController,
didSelectViewController viewController: UIViewController) {
if let vc = viewController as? UINavigationController {
vc.popViewControllerAnimated(animated: false);
}
}
}
Edit: Swift 3 update, thanks to #Justin Oroz for pointing that out.
In Swift 3.1
Add UITabBarControllerDelegate to your TabBar Class:
class YourClass: UITabBarController, UITabBarControllerDelegate {
After:
override func tabBar(tabBar: UITabBar, didSelectItem item:
UITabBarItem) {
let yourView = self.viewControllers![self.selectedIndex] as! UINavigationController
yourView .popToRootViewControllerAnimated(false)
}
What you are trying to do sounds a little bit odd. Have you read the Human Interface Guidelines on combining UINavigationControllers and UITabBarControllers?
However, what you need to do is detect the selection of the tab by setting a delegate for your UITabBarController and implementing the tabBarController:didSelectViewController: delegate method. In this method you need to pop back to the root view controller using UINavigationController's popToRootViewControllerAnimated: method.
Swift 5.1 Answer:
class YourTabBarName: UITabBarController, UITabBarControllerDelegate
{
override func viewDidLoad()
{
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController)
{
if let vc = viewController as? UINavigationController
{ vc.popToRootViewController(animated: false) }
}
}
[self.navigationController popToRootViewControllerAnimated:NO];
Swift 4.2
The solution that works for me is to subclass the UITabBarController and add the two delegate functions as follows:
import UIKit
class MyCustomTabBarController: UITabBarController, UITabBarControllerDelegate {
var previousSelectedTabIndex:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
self.previousSelectedTabIndex = tabBarController.selectedIndex
}
override func tabBar(_ tabBar: UITabBar, didSelect item:
UITabBarItem) {
let vc = self.viewControllers![previousSelectedTabIndex] as! UINavigationController
vc.popToRootViewController(animated: false)
}
}
Make sure you set animated to false otherwise you will get
Unbalanced calls to begin/end appearance transitions for the targeted ViewController
Try this.
class TabBarClass: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let vc = self.viewControllers![selectedIndex] as! UINavigationController
vc.popToRootViewController(animated: false)
}
}
First, you should create subclass of UITabbarController and add Observer:
- (void)viewDidLoad {
[super viewDidLoad];
[self.tabBar addObserver:self forKeyPath:#"selectedItem" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
}
When tabbar is selected, We will process in method:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:#"selectedItem"] && [object isKindOfClass:[UITabBar class]]){
UITabBar *bar = (UITabBar *)object; // The object will be the bar we're observing.
// The change dictionary will contain the previous tabBarItem for the "old" key.
UITabBarItem *wasItem = [change objectForKey:NSKeyValueChangeOldKey];
NSUInteger was = [bar.items indexOfObject:wasItem];
// The same is true for the new tabBarItem but it will be under the "new" key.
UITabBarItem *isItem = [change objectForKey:NSKeyValueChangeNewKey];
NSUInteger is = [bar.items indexOfObject:isItem];
if (is == was) {
UIViewController *vc = self.viewControllers[is];
if ([vc isKindOfClass:[UINavigationController class]]) {
[(UINavigationController *)vc popToRootViewControllerAnimated:YES];
}
}
}
}
The UTabController suggests a different UX for letting a user "pop to root". When switching back to a tab, it keeps the full UINav stack from before. If they tap the bar item a second time (tapping the selected tab), only then does it pop to root. That's all automatic. Some apps, like instagram, allow a third tap to scroll to top.
I'd suggest sticking with the defaults as that's what users will be expecting.
The below had worked for me .This code in swift 3:
1> subclass UITabbarController and implement two below method with one iVAr:
class MyTabBarController: UITabBarController ,UITabBarControllerDelegate {
var previousSelectedTabIndex : Int = -1
}
2> set the tabbar delegate in viewdidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self // you must do it}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
self.previousSelectedTabIndex = tabBarController.selectedIndex
}
func tabBarController(_ tabBarController: UITabBarController,
shouldSelect viewController: UIViewController) -> Bool {
if self.previousSelectedTabIndex == tabBarController.selectedIndex {
let nav = viewController as! UINavigationController // mine in nav_VC
for vc in nav.childViewControllers {
if vc is YUOR_DESIRED_VIEW_CONTROLLER {
nav.popToViewController(vc, animated: true)
return false// IT WONT LET YOU GO TO delegate METHOD
}
}
}
return true
}
tabBarController.selectedIndex give you the selected tab
In tabBarController_shouldSelect_viewController method you can set your desired view controller with some easy calculation.
if you are not getting the above code play with both above method and you come to know how both working together
Use selected view controller to popToRootViewController. Basically you need to cast this instance.
Swift
((selectedViewController) as! UINavigationController).popToRootViewController(animated: false)
//
// I just added extra line so the scroll bar won't annoy you.
Xcode 11.5, Swift 5:
You don't need to use two delegate methods. Only one is enough:
extension CustomTabBarController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if tabBarController.viewControllers?.firstIndex(of: viewController) == tabBarController.selectedIndex,
let navigationController = viewController as? UINavigationController {
navigationController.popToRootViewController(animated: true)
}
return true
}
}
//create a tabbar controller class set it to your TabbarController in storyboard
import UIKit
class MyTabbarViewController: UITabBarController,UITabBarControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController)
{
if let vc = viewController as? UINavigationController
{ vc.popToRootViewController(animated: false) }
}
}