I have something like that :
(1) NavigationController --> (2) UITableViewController --> (3 afted clicked in a cell) UIViewController
So when I receive a push notification, I want to redirect in the view controller ( which display a message )
I'm doing something like :
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
_messageConsult = (MessageConsultDetailViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"seeMoreView"];
_messageConsult.idMessage = [[userInfo objectForKey:#"aps"] objectForKey:#"id_message"];
_messageConsult.navigationController.toolbarHidden = NO;
self.window.rootViewController = _messageConsult;
[self.window addSubview:_messageConsult.view];
[self.window makeKeyAndVisible];
So it display the view well, but without any top/bottom bar. Althought when i'm displaying the view directly from the UITableViewCell, it works
Someone can give me some advice to this problem ?
You don't see it because you're instantiating a new instance of MessageConsultDetailViewController and making that your window's root view controller -- that means, it will be the only view controller in the hierarchy, and the navigation controller(with its navigation and tool bars)and table view controller will be deallocated if you don't have any strong pointers to them. The correct way to display that controller would be to do a push from the table view controller.
By the way, when you make a controller the window's root view controller, you shouldn't also add its view as a subview to the window -- that's already done when you make it the root view controller.
Related
I have been working on this problem for a while and thought I would ask for some help. I have 3 view-controllers: 1 Navigation Controller, 1 Main controller and 1 detail view controller.
Within the main view controller, I have a series of subviews with buttons. Due to the class structure, however, I am unable to directly call self.storyboard to get the current storyboard object.
I have tried 2 different methods, a variety of ways, and am still unsuccessful. I posted my methods below and described what is and what is not happening in each segment. The overall goal is to present a child view controller (the detail view) by tapping a button in a subview, of which does not have access to the parent storyboard directly.
Method 1
//Instantiate the new view controller
ProfileViewViewController *tempViewToShow = [del.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"profile"];
// Pass data into the new view controller
tempViewToShow.thisUser = self.postUser;
// Output a simple log to ensure both were created
NSLog(#"Temp User Name: %#, Profile Desc: %#", [tempViewToShow.thisUser getFullName], tempViewToShow.description);
// Using the AppDelegate for the RootViewController, present the detail view
[UIApplication.sharedApplication.delegate.window.rootViewController presentViewController:tempViewToShow animated:YES completion:NULL];
Issues
The issue with this series is that the detail view does not carry the navigation controller (since it is not mentioned), however, this way still shows a full View Controller
Method 2
...
// Use the Delegate and the navigation controller to present the new view controller
[UIApplication.sharedApplication.delegate.window.rootViewController.navigationController presentViewController:tempViewToShow animated:YES completion:NULL];
Issues
Does not display anything
Method 3
// Use the recommended 'pushViewController' for the navigation controller to carry over
[UIApplication.sharedApplication.delegate.window.rootViewController.navigationController pushViewController:tempViewToShow animated:NO];
Issues
Does not display anything
En toto, how would I make this work? What lines would I modify and how? Thanks!
You can solve this issue like this:
ProfileViewViewController *tempViewToShow = [del.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"profile"];
UINavigationController *naviController = [[UINavigationController alloc] tempViewToShow];
And then do this :
[UIApplication.sharedApplication.delegate.window.rootViewController presentViewController:naviController animated:YES completion:NULL];
You can create instance of storyboard from storyboard name.once you have correct storyboard instance, get NavigationController from Its identifier, and detailviewController from its identifier. Push detailviewcontroller on Navigationviewcontroller.
get storyboard-- replace name of your storyboard in "MainSToryboard"
UIStoryboard *storyboard =
[UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:[NSBundle mainBundle]];
get instance of Navigationcontroller - replace identifier:
UINavigationController *navController =(UINavigationController *)
[storyboard instantiateViewControllerWithIdentifier:#"navcontroller"];
get detailviewconrtoller :
UIViewController *detailvc=
[storyboard instantiateViewControllerWithIdentifier:#"profile"];
Push detail on current navigationcontroller:
[navController pushViewController:detailvc animated:YES];
I found an alternate solution. The cause was because the incorrect view controller was being called by
UIApplication.sharedApplication.delegate.window.rootViewController.*
The workaround is:
In the primary view controller class, I passed the displayed viewcontroller into the delegate class. Then, from the child class I wanted to call, I referenced that view controller, and navigation controller, and it worked just fine. My final code is below:
// Create the detail View Controller
ProfileViewViewController *tempViewToShow = [del.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"profile"];
// Set the user variable in the detail view controller
tempViewToShow.thisUser = self.postUser;
// Push the view controller into the navigation controller
// Note that del.currentNav comes from this code:
/*
* In this class, create the delegate reference
* AppDelegate *del = (AppDelegate *)[[UIApplication sharedApplication] delegate]
*
* In the Delegate class, get the set the current navigation controller {let currentVC : UIViewController = passedInVC}
* self.currentNav = currentVC.navigationController;
*/
[del.currentNav pushViewController:tempViewToShow animated:YES];
There is problem in view hierarchy. Here is flow of my app.
When app starts View Controller "A" is Visible. After that storyboard "B" is loaded through "StoryBoard Reference (Push)" ,Where another navigation controller is present and Home screen is loaded. On Click of Menu button in Home screen Side panel is visible.
Now When i click on side panel menu items view Controller "B" is pushed. This View Controller is Pushed Under Home screen and is not Vsible.
Help View contoller is visible under Home controller. I want Help View Controller should come on top of Home controller.
I dont understand what issue is coming..
Any Help will be appreciated..
If you are pushing view controller from side panel shows in image, will never push because it is not in navigation controller.
the answer depends on how you showing your side menu but from assumptions
what you need to do is to set root view controller or keep reference of navigation controller and push from there
If you are presenting side menu then it is not on navigation controller so you should first dismiss this side menu and on the completion of it you should push new view controller (says B or Help). I am writing my code snippet that i am using in my project for demonstration,
- (IBAction)settingClick:(id)sender {
SettingViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"settingsScreen"];
[self dismissViewControllerAnimated:NO completion:^{
[self.vc.navigationController.navigationController pushViewController:svc animated:YES];
}];
}
Above method push setting view controller on current navigation controller after dismissing side menu
Now important thing is self.vc this is the object of previous viewcontroller (Home controller in your case i think) on which side menu was presented.
So my SideMenuViewController has a property like,
#property (nonatomic,strong) UIViewController *vc;
which i am setting with self from previous view controller (in your case from Home view controller) something like,
SideMenuViewController *smvc = [self.storyboard instantiateViewControllerWithIdentifier:#"sideMenu"];
smvc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:smvc animated:NO completion:^{
smvc.vc = self;
}];
And i have used [self.vc.navigationController.navigationController pushViewController:svc animated:YES]; i.e. two navigation controller to push because i have two navigation controller in my view hierarchy to push this new view controller.
You can manage that as per your setup that how many navigation controller you have !!
Hope this will help :)
After digging a lot, I found solution for this.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Home" bundle: nil];
RootController *someViewController = [storyboard instantiateViewControllerWithIdentifier:#"RootController"];
[self.navigationController pushViewController:someViewController animated:YES];
I have set another navigation controller as root ViewController of the window and it worked for me.
Thanks.
I added a Navigation Controller to my storyboard and it appears like so:
Now in the table view controller, I gave the TableViewController a storyboard id and class to a TableViewController Controller
When I run my app, I don't see the Navigation Bar at the top. This has been extremely frustrating and can't find a solution anywhere. PLEASE HELP
To get to the scene, someone clicks a button and this code runs and it goes to my Table View Controller:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
LHFileBrowser *LHFileBrowser = [storyBoard instantiateViewControllerWithIdentifier:#"FileBrowser"];
[self.navigationController pushViewController:LHFileBrowser animated:YES];
[self presentViewController:LHFileBrowser animated:YES completion:nil];
The error is in your code.
If you want to (modally) present a view controller when the user presses a button, you need to present the navigation controller (which will contain the table view controller), not the table view controller itself.
Right now, you're presenting the view controller, which won't show it being embedded in a navigation controller.
Also, you're mixing up two different approaches, by trying to push a view controller onto a navigation controller stack, and also presenting the view controller.
Code Sample:
Here's what you apparently mean to do:
UIStoryboard *storyboard = self.storyboard;
UINavigationController *navigationController = [storyboard instantiateViewControllerWithIdentifier:#"MyNavigationControllerID"];
LHFileBrowser *rootViewController = [navigationController topViewController];
// Configure your LHFileBrowser view controller here.
rootViewController.someProperty = ...;
// Modally present the embedded view controller
[self presentViewController:navigationController animated:YES completion:nil];
If you want to change the presentation or transition style, you can set those details in your storyboard.
You didn't explain why you had to programmatically add buttons, but Storyboard segues would have instantiated and presented an embedded view controller for you, without you having to have done it in code.
The more you can do in Storyboard, the less code you have to maintain, support, and update, and the more likely your app will still work properly when a new SDK is released.
Update:
The better way to do this is to let Storyboard do it for you, by adding a segue from the button to the navigation controller that you want to present.
on viewdidload of one of my tabbar viewcontrollers I'll like to display or popup another view controller. here's my code
if (_history.count == 0) {
//[self performSegueWithIdentifier:#"emptyHistorySegue" sender:self];
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
MSAEmptyHistoryViewController *popupController = [sb instantiateViewControllerWithIdentifier:#"EmptyHistoryViewController"];
[self presentViewController:popupController animated:NO completion:nil];
}
The load the viewcontroller on top of the tabview controller. I need this view to display but still allow the user to see the tabbar buttons.
You will run into problems if you try to transition to another view controller in viewDidLoad. You should either switch the child view controllers of the tab bar controller or you can present a subview within one of the child view controllers.
When -viewDidLoad is called, the view controller is generally not presented. As such, if you try to present another controller, it will crash.
Try -viewDidAppear: if you want what you are describing.
I have setup a UINavigation controller that uses the AppDelegate as the main point of contact.
I have different methods which run such as presentHomeViewController, presentLoginViewController, which push the different view controllers to the Navigation Controller.
App Delegate - didFinishLaunching
welcomeViewController = [[MyWelcomeViewController alloc] initWithNibName:#"MyWelcomeViewController" bundle:nil];
navController = [[UINavigationController alloc] initWithRootViewController:welcomeViewController];
navController.navigationBarHidden = YES;
self.revealSideViewController = [[PPRevealSideViewController alloc] initWithRootViewController:navController];
[self.revealSideViewController setDirectionsToShowBounce:PPRevealSideDirectionNone];
[self.revealSideViewController setPanInteractionsWhenClosed:PPRevealSideInteractionContentView | PPRevealSideInteractionNavigationBar];
self.window.rootViewController = self.revealSideViewController;
Is this the correct process for this?
- (void)presentHomeViewController {
// We start by dismissing the ModalViewConrtoller which is LoginViewController from the welcomeview
[self.welcomeViewController dismissModalViewControllerAnimated:YES];
// Check if the home view controller already exists if not create one
if (!self.homeViewController) {
NSLog(#"presentHomeViewController- Creating the Home View controller");
homeViewController = [[MyHomeViewController alloc] initWithNibName:#"MyHomeViewController" bundle:nil];
}
// Push the homeViewController onto the navController
NSLog(#"presentHomeViewController");
self.navController.navigationBarHidden = NO;
[self.navController setTitle:#"Home"];
[self.navController pushViewController:homeViewController animated:NO];
If I then add the following to a different class :
[self.navigationController pushViewController:accountViewController animated:NO];
No view is pushed to the stack, should I control all the movement within the AppDelegate as I have been doing, or is there betters way to approach this?
EDIT
Thanks for posting your code. So, to address your final question first, I don't recommend controlling your navigation stack from the app delegate. You should be controlling the stack from the view controllers that are the children of the navigation controller.
To that point, remember the hierarchy of view controllers: UINavigationController inherits from UIViewController, and UIViewController has properties defined for all the things you'd see in a navigation layout such navigation items and title. More importantly, it also has properties for its parent view controllers, the view controller that presented it, and its navigation controller. So, considering the hierarchy, your app delegate should only instantiate the navigation controller's root VC and the nav controller itself, and then subsequently set the nav controller's root VC.
From there, you should be pushing and popping other VCs from the VCs themselves. Remember, every VC has a property that's automatically set to point at the navigation controller it's a part of. That's why [self.navigationController pushViewController:] works. For instance, if I have a nav controller whose root VC is a UITableViewController, and tapping on one of the items in the table view pushed a new VC onto the stack, I would push that VC from the table VC and not from the nav controller class or the app delegate.
Sorry if that's confusing. Please let me know if that needs clarification and I'll give it my best. Otherwise, hopefully that gets you on the right track.