My application has a ViewController i.e. the first screen that opens when app is started. I added a UITabBarController to the application through mainstoryboard. I changed the title of UITabBarController to "myTabBarController". Now how do I access this TabBarController from the viewDidLoad function of already existing ViewController?
amazed! Why do you need view controller if you want to load UITabBarController from viewDidLoad function of view controller???
However solution can be like this:
You can make segue: right click in view controller then drag to tabBarController and select segue "show".
But, better would be if you embed UITabBarController to view controller which loads your TabBarController at the beginning of your app.
1: Select View Controller
2: Go to [Editor] in menu bar of xcode
3: Select Embed In
4: Select Tab Bar Controller
and you are done :)
other solution would be:
delete the ViewController from storyboard
select tabBarController that you added.
go to "attribute inspector" in left pane and select "Is initial View Controller"
ADDED
1. Give identifier to TabBarController like given by 張家齊
2. Add button in ViewController and make Action of it in ViewController's class (to make action. right click the added button and drag to ViewController class and select Action instead of Outlet.)
3. Now add following codes in that action:
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewControllerWithIdentifier("myTabBarController") //vc is instance of TabBarController.
self.presentViewController(vc, animated: true, completion: nil)
DONE :)
In AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let main = storyboard.instantiateViewControllerWithIdentifier("myTabBarController") as! myTabBarController
self.window!.rootViewController = main
self.window!.makeKeyAndVisible()
return true
}
And you should set Identifier of myTabBarController in your Main.storyboard.
Related
Sorry, if it is an essential question.
The scheme is the following:
enter image description here
I want the following:
User taps last Tab
User goes to some ViewController (different from ViewController, actually connected with last Tab)
How to do this (without using segue)?
Thanks a lot in advance!
You can go with instantiateViewController with push when load your tab and push one viewController to another like below:
let next = self.storyboard?.instantiateViewController(withIdentifier: "nextVC")as! nextVC
self.navigationController?.pushViewController(next, animated: true)
You can assign ViewController in you UITabBarController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// create view controllers from storyboard
// Make sure you set Storyboard ID for both the viewcontrollers in
// Interface Builder -> Identitiy Inspector -> Storyboard ID
let clockViewController = storyboard.instantiateViewControllerWithIdentifier("ClockViewController")
let stopWatchViewController = storyboard.instantiateViewControllerWithIdentifier("StopWatchViewController")
// Set up the Tab Bar Controller to have two tabs
let tabBarController = UITabBarController()
tabBarController.viewControllers = [clockViewController, stopWatchViewController]
// Make the Tab Bar Controller the root view controller
window?.rootViewController = tabBarController
I want to send a user to a specific ViewController in my app once a notification is clicked.
I now that I can do something like this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationViewController = storyboard.instantiateViewControllerWithIdentifier("Home") as? HomeViewController
presentedVC?.presentViewController(destinationViewController!, animated: true, completion: nil)
But my app has a tab bar and looks like this
Tab bar
tab1: navigationController -> VC1
tab2: navigationController -> VC2 -> HomeVC
tab: navigationController -> VC3
Each tab has a navigationController as a infront of it.
So how can I send the user to HomeVC? I must first select tab 2 then the navigation controller then push the user tvice:
tab2: navigationController -> VC2 -> HomeVC
And the other problem, if there any way to tell if the user is already in HomeVC? I dont want to send the user to the same VC if his already there.
You must have access to your UITabbarController in you UIApplicationDelegate or wherever you're handling the notification tap.
let tabBar:UITabBarController = self.window?.rootViewController as! UITabBarController //or whatever your way of getting reference is
So first you'll get the reference to UINavigationController in your second tab like this:
let navInTab:UINavigationController = tabBar.viewControllers?[1] as! UINavigationController
Now push your home view at second tab's navigation controller:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationViewController = storyboard.instantiateViewControllerWithIdentifier("Home") as? HomeViewController
navInTab.pushViewController(destinationViewController!, animated: true)
And finally switch your tab to second to show the just pushed home controller
tabBar.selectedIndex = 1
Keep in mind, this answer assumes that your application has already set the tab bar as the root view controller of application window prior handling the notification tap.
Try something like this:
if let tabBarController = window?.rootViewController as? UITabBarController {
tabBarController.selectedIndex = 1 // in your case the second tab
}
The idea is to switch to get the tab bar instance and switch it to your desired tab (where you have your view controller).
The above code works in AppDelegate / you can easily call it anywhere by getting the tabBarController instance.
You can check which tab is selected by user with the method var selectedIndex: Int. You can check which view controller is present like this self.navigationController?.presentingViewController?.presentedViewController. This will solve your problem.
I have a TapBarViewController with three Taps in my project.
Now I am trying to put a normal FirstViewController in front of the TapBar ViewController when the application launches.
The FirstViewController should have three buttons for one of the individual Taps of the TapBarViewController.
How can I show the individual Taps of the TapBarViewController by pressing one of the three buttons?
Screenshot
This is the exact answer you are looking for.
Steps:
Add a UIViewcontroller and embed with UINavigationViewController (Editor -> EmbedIn -> NavigationController).
Add Three button + 1 Button (Navigate to TabViewController).
Drag and drop UITabBarController to the storyboard it comes with one default ViewController and place a UILabel named as 'ButtonOneClicked'.
Create Two more ViewControllers and named as 'ButtonTwoClicked' and 'ButtonThreeClicked'.
Connect 'ButtonOne' with FirstViewController and set segue as Show and repeat the same for rest two.
Click on each segue and provide an unique Identifier name.
Then connect the UITabBarController with each UIViewController and choose viewcontrollers
Create a ButtonAction to the Tab Button.
Copy paste the below code in that action.
#IBAction func tabClicked(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "Tab") as! UITabBarController
appDelegate.window?.rootViewController = initialViewController
appDelegate.window?.makeKeyAndVisible()}
Hope this helps you!!
I have a SplitViewController with a UITableViewController as the masterViewController and a UIViewController as the detailViewController.
When the user taps a cell, I need to push to a new UITableViewController. So I added a segue from the cell to a UITableViewController. But what happens is the UITableViewController gets added to the masterViewController's stack.
How can I push to a whole new UITableViewController from the masterViewController?
Here is a simple example how I approach such functionality (I created a new Master-Detail Application):
Storyboard:
Notice that the root VC is now a UINavigationController. Therefore AppDelegate must be changed accordingly:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let navCtr = self.window!.rootViewController as UINavigationController
let splitViewController = navCtr.visibleViewController as UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as UINavigationController
navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
splitViewController.delegate = self
return true
}
And then finally in MasterViewController add this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if indexPath.row % 2 == 0 {
self.performSegueWithIdentifier("showDetail", sender: nil)
} else {
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
if let let rootCtr = appDelegate.window?.rootViewController {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let newSplit = storyboard.instantiateViewControllerWithIdentifier("SplitVC") as UISplitViewController
/// Because of Apple's "Split View Controllers cannot be pushed to a Navigation Controller"
let yetAnotherNavCtr = UINavigationController(rootViewController: newSplit)
rootCtr.presentViewController(newSplit, animated: true, completion: nil)
}
}
}
Important notes:
If you create new MasterDetail Application from the template, you have to disconnect the showDetail segue, because it is directly linked to the cell's selected callback. If you want to preserve that functionality as well, simply connect it again not from the cell itself, but from the whole VC. To be able to use it as in my funky didSelect... method that performs the showDetail segue on even rows.
The Split View presentation will work only once - I haven't implemented the whole rootViewController replacement - the lldb will complain saying: Attempt to present UISplitViewController on UINavigationController whose view is not in the window hierarchy! if you'll try to do it for the second time. But that's really up to your requirements for how you want the app to behave.
Name the SplitView Controller in Storyboard "SplitVC" (Storyboard ID) if you want to present the Split View Controller like I am doing in my code.
I got it! First I should mention Michal's answer helped me to get an idea and point me in the right direction so thanks to him.
What I did was simple actually. Before I had a View Controller with a container view embedding the split view controller. I simply went ahead and embedded that view controller in a navigation controller.
Then I added the view controller I want to segue to in the storyboard but no segue attached to it. I'm doing it programatically in the masterViewController's didSelectRowAtIndexPath method.
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
if let rootVC = appDelegate.window?.rootViewController {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let mapVC = storyboard.instantiateViewControllerWithIdentifier("MapVC") as! UIViewController
rootVC.showViewController(mapVC, sender: nil)
}
I get a reference to the rootViewController which is a navigation controller through the AppDelegate and I push the new view controller I want to it's stack.
That's it! Here's a demo project in case anyone's interested.
I have a tabbar app with an initial login screen. The tabbarController is set as the initial view in Storyboard with 1 VC that has a navigationController also embed.
I have a loginVC instantiated and set as rootViewController in my AppDelegate. After the user has successfully sign in from the loginVC, I need to switch over to the tabbarController. Would I try to get a reference to the tabbarcontroller and set it as the new rootviewcontroller? If so, I'm having a hard time figuring out how to do this:/
AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if NSUserDefaults.standardUserDefaults().objectForKey("OAuth") == nil {
self.window = UIWindow(frame:UIScreen.mainScreen().bounds)
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var loginVC = storyboard.instantiateViewControllerWithIdentifier("LOGIN_VC") as LoginVC
self.window?.rootViewController = loginVC
self.window?.makeKeyAndVisible()
}
return true
}
This method gets called after user has successfully signed in
func dismissLoginVC() {
var tabbarController = self.storyboard?.instantiateViewControllerWithIdentifier("TABBAR") as UITabBarController
self.presentViewController(tabbarController, animated: true, completion: nil)
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.window?.rootViewController = tabbarController
}
I know the problem with this is it just created a new tabbarcontroller, rather than referencing the existing tabbarController that was set as the initialView in storyboard. This seems to work but it is missing other items from the navigation bar.
Thanks for pointing me in the right direction!
I think you should change your app structure. Keep the tab bar controller as the initial view controller in the storyboard, and present modally (with no animation) the login controller from the viewDidAppear method of the controller in the first tab -- it will be the first thing the user sees. When you dismiss it, you will be back to that controller in the first tab. With this approach, you don't need any code in the app delegate.