I have two view controllers which are defined in storyboard as,
UIViewController -> (Show Detail Segue) -> UITabBarController
My problem is; I am using a library called netfox to debug my HTTP requests. And this librarie's UI is being triggered by Shake Gesture. But when I come to the UITabBarController Shake Gesture on the simulator does not work at first time. At the second time it dismisses the ViewController that is currently on the screen and obviously a child of UITabBarController and goes back to the initial UIViewController. This is exactly like connecting two ViewControllers with modal segue and calling self.dismiss() from the child one.
I tried to change rootViewController of the UIApplication by,
UIApplication.shared.keyWindow.rootViewController = self
in the viewDidLoad() method of the UITabBarController and it worked. However, for this solution, the items(buttons, titles) in the UINavigationBar of any UINavigationController that is the child of UITabBarController are missing.
I have no idea why this is happening. If someone helps me while I am solving this, I would be really appreciated.
Instead of using
self.performSegue(withIdentifier:_)
calling this in the UIViewController have worked:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewControllerWithIdentifier("tabBarcontroller") as UITabBarController
UIApplication.sharedApplication().keyWindow?.rootViewController = viewController;
Respect to this answer.
Related
I have a UITabBarController which is connected to 3 UINavigationControllers. Each of these have a UIViewController as a root view controller. When I click on a button in one of these ViewControllers (VC1), I want it to segue to new ViewController (VC2). Simple enough.
During runtime, when the segue takes place and VC2 appears, the navigation bar disappears.
The navigation bar is present in the storyBoard / interface builder, and the segue is the type: present (Push).
Code in VC1:
#IBAction func create_clicked(_ sender: Any) {
performSegue(withIdentifier: "segueIdentifier", sender: self)
}
It might help to know how the UITabBarController tabBar is instantiated:
func login() {
let storyBoard = UIStoryBoard(name: "Main", bundle: nil)
let tabBar = storyBoard.instantiateViewController(withIdentifier: "tabBar")
window?.rootViewController = tabBar
}
Please help.
After a great deal of experimentation, we determined that even though Interface Builder said this was a Show (Push) segue, and even though we were in a Navigation Controller to start with,
it was behaving as a Present Modally segue.
So we changed the segue type, using the pop-up menu in Interface Builder, from Show (Push) to plain Push, even though that's deprecated — and the interface worked correctly.
And then we changed it back to Show (Push) and the interface continued to work correctly. Problem solved!
I suspect the storyboard was corrupted in some way. Obviously Interface Builder should not lie to you about what kind of segue this is, but basically, that is what it seems to have been doing.
EDIT The problem was caused, apparently, by making a Show Detail segue and changing it to Show. When you do that, it's still a Show Detail segue, which in this context behaves as a modal presentation. That's an Xcode bug! I reported it, and Apple now says this will be fixed in Xcode 9.3.
I am making an app that uses a UIPageViewController for navigation between pages. Everything works fine except that when I am trying to manually change which view controller is shown using setViewControllers it does not show.
I know that it is creating the view controller because it prints to the log, but the controller shown on screen isn't changed. The indexes I use for the subclass of uiviewcontroller that makes each view controller are also set correctly.
The function is called on the press of a view controller.
Here's the code that is supposed to change the controller:
func changeVC(VC: UIViewController) {
setViewControllers([VC], direction: .Forward, animated: true, completion: nil)
}
And the function call:
Let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("contentView") as! ViewController
Controller.index = row
PageViewController().changeVC(controller)
That is inside of the didSelectRowAtIndexPath method of a table view.
Cjay was absolutely correct,
Lemme explain it little more in detail to help you understand what mistake you are doing.
Everytime you call PageViewController().changeVC(controller) new instance of PageViewController will be created and changeVC will be called on that new instance that you have just created. Though your code to instantiate a ViewController from storyboard setting it's index,calling changeVC and setting theViewController of PageViewController everything executes you won't see any of this making any effect on your screen because you changed the ViewController of the PageViewController which you just instiated which neither has a visible valid frame (0,0,0,0) nor it is loaded (not added to your ViewController's view) :)
Rather what you should have done is to do exact same things on a PageViewController which is already loaded :)
As per you comments you are loading the PageViewController from storyboard create an IBOutlet for it lets call it as myPageViewController :) so when you want to change the ViewController of it simply say,
let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("contentView") as! ViewController
controller.index = row
self.myPageViewController.changeVC(controller)
Hope this helps :)
I have a view controller reference to a storyboard of a given identifier. I'm adding a bunch of buttons to it, then trying to display it via a segue.
My problem is that when the segue fires, it creates a difference instance of the view controller with the same segue identifier, and thus it's blank.
What's the best practice to addSubView() to a storyboard, then getting that SAME storyboard object to display?
CLARIFICATION
Here's the flow I'm using:
Central VC -> Create SubVC using centralized Storyboard Object -> Adding SubViews to that SubVC in a factory class -> Queue Segue from SubVC back to the Central VC for segue using its identifier -> [it creates a NEW VC without my additions]
If you're using segues, then the Storyboard creates the destination viewController. If you want to customize the destination viewController, then you do that in prepareForSegue.
You can instantiate a view by code, and pushing in to you navigation controller, it's a clean approach and dont mess the Storyboard with unnecessary segues.
Just instantiate the next view (you must first give this view an StoryBoard ID), call it by code, and push it in the navigation controller.
Objective-C
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"storyBoard_Name" bundle:nil];
UIViewController* controller = [storyboard instantiateViewControllerWithIdentifier:#"ViewController_ID"];
[self.navigationController pushViewController:viewControllerName animated:YES];
Swift
let storyboard = UIStoryboard(name: "storyBoard_Name", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController_ID") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
Short explanation.
I have a ContainerViewController that I'm pushing to a navigationStack.
The ContainerViewController has 2 child UIViewController. A SlidePanelViewController (a slide-out menu) and a CenterViewController (the content), my CenterViewController is a UITabBarController which currently has 2 UIViewController.
I have a button in my menu to that I need to change the UIViewController in my tabBarController. However nothing happens when I call my functions.
Here's the function I am trying to call:
func premiumFormulaTapGesture() {
tabBarController?.selectedIndex = 1
}
(I also tried setting it to 0 and 2. Still with no results.) I tried putting self. in front of it without any luck.
I also tried putting it as a function in my ContainerViewController. But that didn't seem to work either.
Here's how I'm setting up my UITabBarController:
var centerTabBarController: UITabBarController!
in ViewDidLoad():
let tabBarController = UITabBarController()
let suggestionsVC = mySuggestions_VC()
let testVC = detaiLSuggestion_VC()
let controllers = [suggestionsVC,testVC]
tabBarController.setViewControllers(controllers, animated: false)
centerViewController = tabBarController
view.addSubview(tabBarController.view)
addChildViewController(tabBarController)
my tabBarController does show up. And I am able to manually tap the 2 buttons on it, where it switches between the viewControllers as expected. I later plan on hiding the UITabBarController, and use the menu. The UITabBarController is going to be my method of changing UIViewController from the menu.
Also just to clarify. I'm not using storyboards.
Any help changing the viewControllers in my tabBarController would be greatly appreciated!
Phillip Mills didn't post an answer yet. So I'm just closing the open question.
My problem was that there was 2 UITabBarControllers named the same "tabBarController" after changing the name to "menuTabBarController" everything worked fine.
again thanks to Phillip Mills for solving my issue in the comments.
I'm using the ECSlidingViewController for my navigation menu, whenever I want to push a UIViewController from this menu, the UINavigationController of the pushed UIViewController is always nil.
The UINavigationController is initialized, the NSLog output shows the following <UINavigationController: 0x8a80770> address. When I call the method pushViewController:animated the UIViewController gets pushed but the UINavigationController is nil, therefore I can't see the UINavigationBar in this controller.
Here is the code snippet I'm using for this:
RecommendationsViewController *rvc = [self.storyboard instantiateViewControllerWithIdentifier:#"RecommendationsViewController"];
[self.transitionsNavigationController pushViewController:rvc animated:NO];
self.slidingViewController.topViewController = rvc;
In viewDidLoad the transitionNavigationController get's initialized with (please note the slidingViewController is from the ECSlidingViewController project on github https://github.com/ECSlidingViewController/ECSlidingViewController and is of type ECSlidingViewController):
self.transitionsNavigationController = (UINavigationController *)self.slidingViewController.topViewController;
Thanks for any help!
I think you have misunderstood how this is suppose to work.
The UINavigationController has to be the topViewController.
Don't reassign the topViewController after you do a push. By doing this:
self.slidingViewController.topViewController = rvc;
All that is going to do is set the current window to display that UIViewController, thats why you didn't see the nav bar, the app needs to display the UINavigationController which in turn will manage a list of UIViewController's
The navigation controller handles a stack of viewControllers, just push the new UIViewController and nothing else
There is a related issue where a Navigation controller's topViewController will forget that it is attached to a navigationController.
My Storyboard setup is: ->NavigationController->ViewController
The connection between NavController and ViewController is "root view controller".
I have set a storyboardID for each of these view controllers.
I have a view management class "ViewManager" that contains weak references to all storyboard views, which I obtain using:
_rootNC = [self.mainStoryboard instantiateViewControllerWithIdentifier:#"NavController"];
//ViewController gets auto-attached to the NavController, and so viewController.navigationController == NavController
_firstVC = [self.mainStoryboard instantiateViewControllerWithIdentifier:#"ViewController"];
//Instantiating the ViewController again clears its navigationController property, and so viewController.navigationController == nil
I suppose one shouldn't gain a hook into Storyboard Instances by reinstantiating the views. I'd appreciate if others would share their best-practices for obtaining weak references to storyboard viewControllers in such a way that I could control them in a single viewManager class. (I'm leaning toward setting viewManager.rootNC from within NavigationController's viewDidLoad).