Re-Presenting Modal View Brings to last VC instead of first - iphone

I have a Navigation Controller that is presented modally with 4 views in the stack. The final view has a done button that dismisses the modal view. When I then present the modal view again, it automatically goes to that last view instead of the first one. I added a line to pop to first view after dismissed but it adds a weird animation whether I set it to YES or NO. Maybe I'm doing it wrong?
- (void)dismissModalView
{
[self dismissModalViewControllerAnimated:YES];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:([self.navigationController.viewControllers count] -4)] animated:YES];
}
Update:
This is the method used to present the modal view/navcontroller
- (void)showModalView
{
self.optionsNavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.navigationController presentModalViewController:self.optionsNavController animated:YES];
}

No, it looks right. If you want to retain the state of the Navigation controller then don't present it modally as it will get deallocated when you dismiss the view.
Modal views are usually used to present information that only needs to be shown briefly without maintaining the state of the view (i.e. about page, login page, settings page, etc).

Excuse me if I'm oversimplifying your issue, but if your need is to pop straight back to the first view controller, perhaps you could give the popToRootViewControllerAnimated: method a try instead of popToViewController:.

I'm not sure what the problem with the dismiss code you posted is, but the following should work:
- (void)showModalView
{
self.optionsNavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.optionsNavController popToRootViewControllerAnimated:NO];
[self.navigationController presentModalViewController:self.optionsNavController animated:YES];
}
Also, viewDidLoad is intended to only be called once every time the view is loaded, viewWillAppear a

Related

Set Previous View Controller As A Property Of The Current View Controller

So, I am trying to implement a swipe right to go back to the previous view controller feature.
But when I have the following code in my current view controller, I get a black screen
- (void)initPreviousViewController:(GGMainViewController *)previous
{
self.previousViewController = previous;
self.previousViewController.view.frame = self.currentView.bounds; //self.currentView is declared elsewhere (in the init of the current view controller)
[self addChildViewController:self.previousViewController];
[self.currentView addSubview:self.previousViewController.view];
[self.previousViewController didMoveToParentViewController:self];
{
^I call this method within the previous view controller after initializing the current view controller, and before pushing the current view controller
If I change self.previousViewController = previous; to self.previousViewController = [GGMainViewController alloc] init]; it works. However, I don't want to reinitialize the previous controller.
So how do I set the previous view controller as a property of the current view controller.
Oh, I am also an iOS first timer, so if this is not something that is recommended, please let me know.
Rationale behind my thinking:
Normally the user would just click a button, and the UINavigationController would do the trick, but since I am using a swipe functionality, I think the user needs to see the previous view controller behind the current view controller as they swipe the screen.
As requested
How I call the currentViewController from the previousViewController
- (void)displayCurrentViewController:(id)sender
{
GGNextViewController *next = [[GGNextViewController alloc] init];
[next initializeExploreViewController:self]; // If I comment this out, everything is ok (screen is not black,etc. apart from being able to swipe backwards
[self.navigationController pushViewController:next animated:YES];
}
Your using the self.navigationController for pushing the current view controller, So you can call a method when ever the right swipe gesture fired.
Try this code in your Current view controller(GGNextViewController.m)...
1. Add the rightSwipeGestureAction() selector to the gesture recognizer which you have.
2.
-(void)rightSwipeGestureAction
{
[self.navigationController popViewControllerAnimated:YES];
}
It turns out that the following lines were causing the problem. I just decided to comment them out and then it worked, without a black screen.
[self addChildViewController:self.previousViewController];
[self.previousViewController didMoveToParentViewController:self];
I can't just pop it with the navigation controller, because I want to create somewhat of a dragging effect, the user swipes (as they see the previous view controller below) until halfway through the screen, from where it goes to the previous view controller.

Go to first view controller in app

I need to go to the first view in my app. I have a few views pushed onto the stack then a modal navigation controller and more views pushed onto that.
The problem I'm having is that using [[self navigationController] popToRootViewControllerAnimated:YES]; only goes back to the first view in the modal stack.
And I can't get [[self navigationController] popToViewController:.. to work because the true first view controller isn't accesible with [[self navigationController] viewControllers].
Any ideas on how to accomplish this? Thanks.
Do this:
[[self navigationController] dismissModalViewControllerAnimated:YES];
That will get you back to the VC that modally presented the navigation controller. Getting farther back after that depend on how you pushed those "few views" before the navigation controller.
Edit - explanation to get to the deepest root...
It sounds like those "few views" are on another, underlying navigation controller's stack. This can be a little tricky, because the clean way to get farther back in that stack is to have that underlying navigation controller pop to it's own root. But how can it know that the modal VC on top of it is done?
Let's call the view controller that did the modal presentation of second navigation controller VC_a. It's a modally presented navigation controller whose topmost VC is VC_b. How can VC_a know to pop to it's navigation root when VC_b modally dismisses itself?
The good answer (usually) is that VC_b decided to dismiss itself for a reason - some condition in your app/model changed to make it decide to be done.
We want VC_a to detect this condition, too. When VC_b gets dismissed, and VC_a gets a viewWillAppear message because it's about to be uncovered:
// VC_a.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (/* some app condition that's true when VC_b is done */) {
// I must be appearing because VC_b is done, and I'm being uncovered
// That means I'm done, too. So pop...
[self.navigationController popToRootViewControllerAnimated:NO];
} else {
// I must be appearing for the normal reason, because I was just pushed onto the stack
}
}
You need to do it by using the delegation pattern. Specifically, by creating a protocol that implements the delegate's respondsToSelector method.
See this post for complete details. It should be almost exactly what you are looking for. I had to do something similar, except I only needed to pop one view off the navigation stack instead of using popToRootViewControllerAnimated:.
For iOS6...
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
In AppDelegate.m class create method with bellow flow...
-(void)MethodName{//your method name
YourViewController *objViewController = [[[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil] autorelease]; ///define your viewcontroller name like "FirstViewController"
UINavigationController *yourNavigationController = [[[UINavigationController alloc] initWithRootViewController:objViewController] autorelease];
self.window.rootViewController = yourNavigationController;
}
When you want redirect on firstview just call this method from appdelegate object....

I can came back to first navigation control page with a button?

-(IBAction) btnReturn:(id) sender{
firstView * firstview =[[firstView alloc]initWithNibName:#"firstView" bundle:nil];
[self.view pushViewController:firstview animated:NO];
}
with the previsly code I see the first view but the navigation control increment. I wold came bak as was the navigation starting point. Any help?
pushViewController:animated: will add to the navigation stack; you want popViewControllerAnimated: to go back one view in the stack.
If you want to return to the very first (root) view controller, you want popToRootViewControllerAnimated:.
See: https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UINavigationController_Class/Reference/Reference.html
In your above code you are pushing a controller on self.view (firstView, I am considering it as controller as you are creating it using initWithNibName: method, but you should you proper naming conventions to avoid confusions.) But view do not have any such method pushViewController:. Instead you sould use if you really have self (the controller in which you are using this IBAction) in navigation stack.
[self.navigationController pushViewController:firstview animated:NO];
To pop controller from navigation stack, follow what #gregheo suggested.
Try using popViewControllerAnimated instead:
- (IBAction)btnReturn:(id)sender
{
[self.navigationController popViewControllerAnimated:NO]; // Or Yes if you would like to have an animation.
}

pushViewController only works with animated:YES

I have found a strange behaviour when trying to push a viewcontroller onto the stack. The following works fine:
[self.navigationController pushViewController:myViewController animated:YES];
but if I change it to animated:NO it no longer works, doesn't seem to push at all. I was performing this in a viewWillAppear but I have also tried it in viewDidAppear but with no luck.
Any ideas what could be causing this?
Thanks
The problem is most probably not the call itself, but the placement of the call. Try putting the same action on a UIButton and it should 100% work. I've noticed that putting view controller manipulation routines like presentModal... and pushViewController... don't sometimes work in the viewWill* viewDid* methods. Or try making the calls from those functions with a performSelector:withObject:afterDelay after a short delay and see if that works.
Edit: there are a couple of ways of doing what you want to do. You can directly modify the navigation stack of a navigation controller, so when you are in view N+1, you can replace view N on the stack (by building a new navigation stack array and setting it in to the navigation controller), then pop, and you'll get the effect of "popping back to a different view controller". You can also issue multiple pops and pushes from the view controller you want to leave, but you have to be careful:
// pop back 2 controllers on the stack to the setup screen
//
// locally store the navigation controller since
// self.navigationController will be nil once we are popped
//
UINavigationController *navController = self.navigationController;
// retain ourselves so that the controller will still exist once it's popped off
//
[[self retain] autorelease];
// Pop back 2 controllers to the setup screen
//
[navController popViewControllerAnimated:NO];
[navController popViewControllerAnimated:YES];

How to jump to a specific view?

I have 3 views (xib'd) the third view opens a modal view (also xib'd).
My goal is to dispose the modal view and jump on the view #1.
I used the following code but it does nothing.
self.statusView = [[StatusViewController alloc] initWithNibName:#"StatusViewController" bundle:nil];
[self.navigationController popToViewController:self.statusView animated:YES];
[self.navigationController popToViewController:
I also tried the following, same result.
[self.navigationController.viewControllers objectAtIndex:0] animated:YES];
I'm going crazy...
statusView has an accessor regularly synthetized and it represents the view that I want to jump to.
It is not entirely clear how your views are set up with respect to each other, based on what you've said so far.
I'm guessing you have a navigation controller, and 3 view controllers that are displayed on the navigation stack.
If that's the case, and you want to pop back by two screens at once (from #3 to #1, skipping #2), then you need a pointer to the view controller for #1 (not the view itself). It looks as if the first popViewController: method call in your question is sending in a view.
Sample code to pop to the first view controller:
UINavigationController* navController = self.navigationController;
UIViewController* controller = [navController.viewControllers objectAtIndex:0];
[navController popToViewController:controller animated:YES];
If you've tried this, and it doesn't work, a few things might be going wrong:
Maybe self.navigationController isn't actually the right object.
Maybe the view you expect isn't actually view #0 on the navigation stack.
Maybe the navigation controller you're working with isn't currently visible.
Here are some further steps you can take to test these hypotheses:
When you first allocate the navigation controller you want to work with, call NSLog(#"Nav controller is at %p", navController); and in this code add a call to NSLog(#"Now my navController is at %p", navController); and check that the addresses match.
If the nav controller is the right one, print out the current navigation stack; something like this (which assumes each view controller has a different class name):
for (UIViewController* viewController in navController.viewControllers) {
NSLog(#"%s", class_getName([viewController class]));
}
Do something visual to the navigation controller you think is visible to make sure it actually is. For example [navController.visibleViewController.view addSubview:aColorFulView]; where aColorFulView is some visually obvious UIView.
-popToViewController lets you pop controllers OFF the stack. What you want to do is push new viewControllers ONTO the stack, so use:
[self.navigationController pushViewController: self.statusView animated: YES];