I would like to have my application have custom buttons in the CameraViewController; one pushes to Rustles ViewController (Top VC in photo below) and the other transitions to ViewController (Bottom VC).
Right now my application can properly segue to the viewControllers by using the following method:
-(void)segueToRustlesTableViewController{
if (debug==1) {NSLog(#"Running %# '%#'", self.class, NSStringFromSelector(_cmd));} // simple debug statement, can ignore
// Instantiate nav controller which segues to table view
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil]; // must assume only IPhone
RustlesTableViewController *rustlesTVC = (RustlesTableViewController *)[storyboard instantiateViewControllerWithIdentifier:#"RustlesView"];
[self performSegueWithIdentifier:#"tableSegue" sender:self];
[self.PickerController presentViewController:rustlesTVC animated:NO completion:nil];
}
However when I get to the UIViewControllers I can't transition back to the old UIViewControllers, presumably because I have no Navigation Controllers embedded in each UIViewControllers.
My code right now wouldn't work for a NavigationController but I don't really know how to transition to the NavigationController and then the UIViewControllers after the Navigation Controller.
How do I transition from CameraViewController to aNavigationController and then to the RustlesViewController?
If you aren't making use of a navigation controller, I would make a custom button in the spawned view controller (Rustles, View) and call
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
I believe this should work.
Related
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'm building a complex app that has kind of a branch in the middle.
At some point in the app, a particular UIViewController is presented, we'll call it mainViewController (shortened mainVC).
The mainVC presents another view controller, by code, using the following code (I strip out parts of it for privacy reasons):
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"SecondaryStoryboard" bundle:secondaryBundle];
SecondViewController *secondVC = [storyboard instantiateInitialViewController];
[self presentViewController:secondVC animated:YES completion:nil];
So the secondVC will later present another view controller, called thirdVC. This is done using a custom segue, set in the storyboard used in the code above, which code looks like this:
#implementation VCCustomPushSegue
- (void)perform {
UIView *sourceView = ((UIViewController *)self.sourceViewController).view;
UIView *destinationView = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
destinationView.center = CGPointMake(sourceView.center.x + sourceView.frame.size.width, destinationView.center.y);
[window insertSubview:destinationView aboveSubview:sourceView];
[UIView animateWithDuration:0.4
animations:^{
destinationView.center = CGPointMake(sourceView.center.x, destinationView.center.y);
sourceView.center = CGPointMake(0 - sourceView.center.x, destinationView.center.y);
}
completion:^(BOOL finished){
[self.sourceViewController presentViewController:self.destinationViewController animated:NO completion:nil];
}];
}
#end
As you can see this segue presents the destination view controller modally (by the use of presentViewController:) with a custom animation (a slide from right to left).
So basically up to here everything is fine. I present the secondVC with a classic modal animation (slide up from bottom) and present the thirdVC with my custom transition.
But when I want to dismiss the thirdVC, what I want is to go back directly to the mainVC. So I call the following from the thirdVC :
self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:_animate completion:nil];
That way, I'm calling dismissViewControllerAnimated: directly on mainVC (referenced by self.presentingViewController.presentingViewController), and I'm expecting the thirdVC to be dismissed with an animation, and the secondVC to just disappear without animation.
As Apple says in the UIViewController Class Documentation:
The presenting view controller is responsible for dismissing the view
controller it presented. If you call this method on the presented view
controller itself, it automatically forwards the message to the
presenting view controller.
If you present several view controllers in succession, thus building a
stack of presented view controllers, calling this method on a view
controller lower in the stack dismisses its immediate child view
controller and all view controllers above that child on the stack.
When this happens, only the top-most view is dismissed in an animated
fashion; any intermediate view controllers are simply removed from the
stack. The top-most view is dismissed using its modal transition
style, which may differ from the styles used by other view controllers
lower in the stack.
The issue is that it's not what happens. In my scenario, the thirdVC disappears, and shows the secondVC being dismissed with the classic modal slide to bottom animation.
What am I doing wrong ?
Edit :
So #codeFi's answer is probably working in a classic project, but the problem here is that I'm working on a framework. So mainVC would be in a client app, and the secondVC and thirdVC are in my framework, in a separate storyboard. I don't have access to mainVC in any other way than a reference to it in my code, so unwind segues are unfortunately not an option here.
I've been having this exact same issue, and I've managed to visually work around it by adding a snapshot of the screen as a subview to secondVC.view, like so:
if (self.presentedViewController.presentedViewController) {
[self.presentedViewController.view addSubview:[[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO]];
}
[self dismissViewControllerAnimated:YES completion:nil];
Not pretty, but it seems to be working.
NOTE: if your secondVC has a navigation bar, you will need to hide the navigation bar in between snapshotting the screen and adding the snapshot as a subview to secondVC, as otherwise the snapshot will appear below the navigation bar, thus seemingly displaying a double navigation bar during the dismissal animation. Code:
if (self.presentedViewController.presentedViewController) {
UIView *snapshot = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
[self.presentedViewController.navigationController setNavigationBarHidden:YES animated:NO];
[self.presentedViewController.view addSubview:snapshot];
}
[self dismissViewControllerAnimated:YES completion:nil];
I had the same issue and I've fixed it by using UnwindSegues.
Basically, all you have to do is add an IBAction Unwind Segue method in the ViewController that you want to segue to and then connect in IB the Exit action to your Unwind Segue method.
Example:
Let's say you have three ViewControllers (VC1, VC2, VC3) and you want to go from VC3 to VC1.
Step 1
Add a method to VC1 like the following:
- (IBAction)unwindToVC1:(UIStoryboardSegue*)sender
{
}
Step 2
Go in Interface Builder to VC3 and select it. Then CTRL-drag from your VC icon to Exit icon and select the method you've just added in VC1.
Step 3
While still in IB and with VC3 selected, select your Unwind Segue and in the Attributes Inspector add a Segue Identifier.
Step 4
Go to VC3 where you need to perform your segue (or dismiss the VC) and add the following:
[self performSegueWithIdentifier:#"VC1Segue" sender:self];
I have a storyboard in my application with a navigation controller and several views. This automatically puts a navigation bar with a back button into any views that are not the root view.
However, sometimes I navigate away from this storyboard to an individual nib. I want to navigate back to the storyboard, but not necessarily to the original root view. I currently use this method to do so:
+(void) TransitionOnStoryboard:(NSString*)storyboard to:(NSString*)identifier withViewController:(UIViewController*)viewController
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:storyboard bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:identifier];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[viewController presentViewController:vc animated:YES completion:NULL];
}
This shows the view I want but without the navigation bar. How do I specify my navigation controller or root view, such that the app knows to put a navigation bar with a back button in?
Thanks
The answer is to leave your navigation controller underneath the view controller you add from a nib.
Present the nib as a full0-screen modal. That gets rid if your navigation bar, as desired. From that new view controller, you can push more modals, add a navigation controller, or whatever.
Note that you could do all of this and stay inside your storyboard as well.
Once you are done, dismiss the modal to reveal your navigation controller, and you are back in business with your storyboard. You can push a new view controller onto your navigation controller without animation and it should appear as the front-most VC when you pop the modal that came from a nib.
I'm sure that this isn't the ideal way to solve this problem, but it did work very nicely for me.
Essentially, I removed all the views from the view controller that had been generated since I navigated away from the storyboard, but before the current view and popped the current view. In this case, these views were of one class (CheckboxListViewController) and so could be removed quite simply as below:
+(void) navigateToMainMenu:(UINavigationController*)navigationController
{
[QuickView removeFromNavigationController:navigationController allOfViewControllerWithClass:[CheckboxListViewController class]];
[navigationController popViewControllerAnimated:YES];
}
+(void) removeFromNavigationController:(UINavigationController *)navigationController allOfViewControllerWithClass:(Class)viewControllerClass
{
NSMutableArray *keptViewControllers = [[NSMutableArray alloc]init];
for (UIViewController *viewController in navigationController.viewControllers)
if (![viewController isKindOfClass:viewControllerClass])
[keptViewControllers addObject:viewController];
navigationController.viewControllers = keptViewControllers;
}
(note- QuickView is the name of the class that contains these methods.).
Any other classes that you do not want your pop to navigate back to can be removed by calling:
[QuickView removeFromNavigationController:navigationController allOfViewControllerWithClass:[YourClassName class]];
In the navigateToMenu method.
I have a login screen, and after auth, I have a tab bar controller with navigation controllers for each views, which I want to present.
Here is the code I use
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UITabBarController *obj=[storyboard instantiateViewControllerWithIdentifier:#"tabBar"];
self.navigationController.navigationBarHidden=NO;
[self.navigationController pushViewController:obj animated:YES];
Problem is The tab bar is not showing. Also, how can I specify to show the second view in the tabbar controller if I needed to?
I am using storyboard.
thanks for any help.
Instead of pushViewController, do a [self presentViewController:(UIViewController *) animated:(BOOL) completion:^(void)completion]
This will show the new view controller as full screen.
You can also create a named segue from the login screen to the tab controller with a modal transition style. You could then call [self perfromSegueWithIdentifier:#"YOUR SEGUE NAME" sender:nil];
To load the 2nd tab in the tab bar, you can do
[self.tabBarController setSelectedIndex:1]
to select the 2nd tab.