Can't push view controller in AppDelegate with TabBarController - ios

I have a TabBarController as a rootViewController for my app. And I'm trying to push view controller when user clicks to notification. But code isn't working. How can I push view controller from AppDelegate without storyboards.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = TabBarController()
window?.makeKeyAndVisible()
return true
}

You can try to embed the tab inside a navigation
let nav = UINavigationController(rootViewController: TabBarController())
nav.isNavigationBarHidden = true
window?.rootViewController = nav
Then inside didReceiveRemoteNotification
if let nav = self.window?.rootViewController as? UINavigationController {
nav.pushViewController(////
}
to show nav inside the vc viewDidLoad
self.navigationController?.isNavigationBarHidden = false

You should not embed UITabBarController in a UINavigationController (as written in Apple Documentation init and push). However, it's working.
The correct solution is to use UINavigationController as tabs in UITabBarController:
let tabBarController = TabBarController()
tabBarController.viewControllers = [UINavigationController(rootViewController: vc1), UINavigationController(rootViewController: vc2)]
window?.rootViewController = tabBarController
and then push to them:
let navigationController = tabBarController.selectedViewController as? UINavigationController
navigationController?.pushViewController(notificationViewController)
Or you can create a new view controller and settng it as a rootViewController of window:
window?.rootViewController = notificationViewController
But this requires more navigation code to setting back tabBarController after dismissing notification etc.

Related

Navigation bar is not displayed in Swift 5

I've been working on an iOS app and I'm trying to display a navigation bar to my app. I use a storyboard to just work on some basic UI, but for the other part like the navigation bar, I'm trying to implement it by code.
In the AppDelegate.swift file, I put the following code.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
UINavigationBar.appearance().tintColor = .black
window?.rootViewController = FirstViewController()
window?.rootViewController?.view.backgroundColor = UIColor.white
window?.makeKeyAndVisible()
return true
}
However, the navigation bar doesn't appear on FistViewController.
In the FirstViewController, I also put the following code into the viewwillappear function to display the navigation bar.
self.navigationController?.isNavigationBarHidden = false
self.navigationController?.navigationBar.barStyle = .black
As I said, I have a storyboard, but I only use it for setting FirstViewController as isInitialView controller. I also have a table view on the FirstViewController and I can see it, but I don't see the navigation bar.
So I was wondering if I make a mistake in writing code to display the navigation bar...
Does anyone know what I'm missing in here?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let viewController = FirstViewController()
let navigationController = UINavigationController(rootViewController: viewController)
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
let viewController = FirstViewController()
let navVc = UINavigationController(rootViewController: viewController)
window?.rootViewController = navVc
You can not see your navigation bar because you are not embedding your current viewcontroller in to a navigation controller.
Since you are using storyboard you should embed your ViewController in a Navigation controller. You can do that by,
first opening your Main.storyboard file
Select your initial ViewController
Going into Editor > Embed in > Navigation Controller
or you could do it programmatically by refering #jignesh's answer

Set UITabBarController as rootViewController

I have a UITabBarController and I want to show this screen and not the login screen if the user session is still active.
My UITabBarController has 3 ViewControllers and the problem is that I don't see the TabBar links in the bottom and I'm unable to navigate.
Without the following code everything works fine. I mean after login I can navigate.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
if Auth.auth().currentUser != nil {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = HomeTabBarController()
}
return true
}
I have also tried the following code to set the rootViewController but it's the same problem.
When I try to set one of the other view controllers as root (one of the children), the Tab Bar doesn't show at all
var rootView: MyRootViewController = MyRootViewController()
if let window = self.window{
window.rootViewController = rootView
}
What am I doing wrong here?
I was facing same issue and I came across your post, the problem with your code is that HomeTabBarController() is creating a whole new TabBarController so to fix it try the following approach I used.
if Auth.auth().currentUser != nil {
print("******************************User Present******************************")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// create view controllers from storyboard
// Interface Builder -> Identitiy Inspector -> Storyboard ID
// Set up the Tab Bar Controller to have two tabs
let tabBarController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarController") as! HomeTabBarController
// Make the Tab Bar Controller the root view controller
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
}
Edit Make sure to add the Identifier to your TabBarController
// Interface Builder -> Identitiy Inspector -> Storyboard ID
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//// this code changes the initial point of aap///////
window = UIWindow(frame: UIScreen.main.bounds)
let nav = UINavigationController()
let myview = SettingTabbar()
nav.viewControllers = [myview]
window?.rootViewController = nav
window?.makeKeyAndVisible()
return true
}
And Function SettingTabbar is:
func SettingTabbar()->(UITabBarController)
{
//Setting TabBar
let tabbar = UITabBarController()
//Designing Tabbar Item Images
let table = UITabBarItem(title: nil, image:UIImage(named: "002-list") , tag: 0)
let collection = UITabBarItem(title: nil, image: UIImage(named: "001-collect"), tag: 1)
let insert = UITabBarItem(title: nil, image: UIImage(named: "add"), tag: 2)
//Getting TabBar ViewControllers
let TableView = newViewController()
let CollectionView = PersonCollectionViewController()
let InsertRec = nextViewController()
//Setting ViewControllers on TabBar Items
TableView.tabBarItem = table
CollectionView.tabBarItem = collection
InsertRec.tabBarItem = insert
let controllers = [TableView,CollectionView,InsertRec]
tabbar.viewControllers = controllers
tabbar.viewControllers = controllers.map{UINavigationController(rootViewController: $0)}
//Setting Title
tabbar.navigationItem.title = "Person Record"
return tabbar
}
The problem is this line:
window?.rootViewController = HomeTabBarController()
That is the wrong HomeTabBarController. It is a totally new HomeTabBarController with no children. You need to fetch the HomeTabBarController that’s in the storyboard.
I finally found the solution: As #matt suggested I had to fetch the HomeTabBarController that’s in the storyboard.
window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
// controller identifier sets up in storyboard utilities
// panel (on the right), it called Storyboard ID
let viewController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarController") as! HomeTabBarController
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
window?.makeKeyAndVisible()
window?.rootViewController = viewController

Tabbar won't hide when pushed into a ViewController inside a UITabBarController

For the purpose of this question, I'm showing a stripped down version of my view hierarchy. My app contains a UITabBarController as the base. Each tab's top most view controller is a navigation controller and it has view controllers embedded in each of them.
Let's take the first tab.
UITabBarController -> UINavigationController -> UITableViewController -> UIViewController
Let's say the UITableViewController instance is some sort of a list and the UIViewController is the detail view. When the user taps on an item from the list, it takes you to the detail view. And when that happens I have set the UIViewController's hidesBottomBarWhenPushed property to true so that the tabbar at the bottom would hide when the user is in the detail view.
My app receives push notifications. When tapped on them, it should open directly into the detail view. I can get it to navigate there. But the issue is the tabbar at the bottom is still visible!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
window = UIWindow(frame: UIScreen.main.bounds)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "TabBarController") as! TabBarController
if openingFromPush {
let firstNavigationController = storyboard.instantiateViewController(withIdentifier: "FirstNavigationController") as! UINavigationController
let tableViewController = storyboard.instantiateViewController(withIdentifier: "TableViewController") as! TableViewController
let viewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
viewController.hidesBottomBarWhenPushed = true
firstNavigationController.viewControllers = [tableViewController, viewController]
tabBarController.viewControllers?[0] = firstNavigationController
// tabBarController.tabBar.isHidden = true
window?.rootViewController = tabBarController
} else {
window?.rootViewController = tabBarController
}
window?.makeKeyAndVisible()
return true
}
I set that same hidesBottomBarWhenPushed property to true in the when I instantiate the view controller but that doesn't seem to have any effect. I even tried straight up hiding the tabbar like this tabBarController.tabBar.isHidden = true but that doesn't do anything at all either.
I can't figure how how to resolve this. Any help would be appreciated.
I attached a sample Xcode project here as well if that helps.
You can use this code for pushing detail view controller:
if openingFromPush {
let viewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
viewController.hidesBottomBarWhenPushed = true
if let nvc = tabBarController.viewControllers?[0] as? UINavigationController {
nvc.pushViewController(viewController, animated: false)
}
window?.rootViewController = tabBarController
}
You don't need to init navigation view controller and table view controller again its already inside tab bar controller

How to set rootview in tabbar controller and show tabbar in each view controller in swift ios?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.backgroundColor = UIColor.white
let tabBarController = self.window!.rootViewController as! UITabBarController
let tabBar = tabBarController.tabBar as UITabBar
let tabBarItem0 = tabBar.items![0] as! UITabBarItem
let tabBarItem1 = tabBar.items![1] as! UITabBarItem
let tabBarItem2 = tabBar.items![2] as! UITabBarItem
let tabBarItem3 = tabBar.items![3] as! UITabBarItem
tabBar.barTintColor = UIColor(red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0)
tabBarItem0.title = "Home"
tabBarItem1.title = "Search"
tabBarItem2.title = "User"
I am new to swift. I have configured the tab bar controller in appdelegate.Now I need to set the rootview controller here and I need to show the tabbar in all my viewcontrollers that I declare.
This will help you. Try to set navigation inside of tab bar controller. Give tab bar item to navigation controller. Like:
Output is:
When you press button:
You can create tabbarcontroller like below, using Xib
//MARK: didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let tabBarController = UITabBarController()
let tabViewController1 = FirstTabViewController(nibName: "FirstTabViewController", bundle: nil)
let tabViewController2 = SecondViewController(nibName:"SecondViewController", bundle: nil)
tabViewController1.tabBarItem = UITabBarItem(title: "Home", image: UIImage(named: "home_icon"),tag: 1)
tabViewController2.tabBarItem = UITabBarItem(title: "Search",image:UIImage(named: "search_icon") ,tag:2)
tabBarController.viewControllers = [tabViewController1,tabViewController2]
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
As per my understanding, you want to achieve something like this :
UITabBarController --> for each tab there will be a navigation controller whose Root will be a VC having tab bar
So I would suggest you to directly use UITabBarControllers for your each root of navigation controller.
That means your root will be UITabBarController, then for each tab there will be UINavigationController whose first view controller will be again a UITabBarController.
For more understanding see below figure. It's only showing flow for one tab of UITabBarController. Repeat the same for all your other tabs.

self.navigationController is always nil

UI flow:
AppDelegate
-->
LoginViewController (not in the storyboard)
-->
navigation controller (in the storyboard)
-->
PFQueryTableViewController (in the storyboard) named "OrdersVC"
This is the navigation controller with OrdersVC:
This is my AppDelegate:
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// ...
// initial VC
let VC = LoginViewController()
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window!.rootViewController = VC
window!.makeKeyAndVisible()
return true
}
The above works fine. Then, from LoginViewController, I am then trying to display my storyboard's initial VC which is a navigation controller hosting a PFQueryTableViewController. Note that LoginViewController is not in the storyboard.
let destVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("OrdersVC") as! UITableViewController
// will throw "unexpectedly found nil"
let navController = UINavigationController(rootViewController: destVC)
navController.pushViewController(destVC, animated: true)
// will throw "unexpectedly found nil"
self.presentViewController(navController, animated: true, completion: nil)
Problem is that in my PFQueryTableViewController's viewDidLoad and viewDidAppear the following statement is always nil:
// navitaionController is nil
self.navigationController!.navigationBar.translucent = false
So how can I correctly instantiate PFQueryTableViewController inside its navigation controller?
You are instantiating the OrdersVC instead of instantiating the navigation controller into which it is embedded and which is the "initial" view controller of your storyboard. Use instantiateInitialViewController instead of using the identifier.
let nav = storyboard.instantiateInitialViewController()
self.window!.rootViewController = nav
The reason for the confusion is that you are "unlinking" the initial view controller from the storyboard with your login controller. You have to add the initial view controller back to the main window.

Resources