Reputation: 67
I am a novice programmer for the iPhone. In developing my first game/app, I have come up with a problem (created a problem) for myself. I have researched this and think I have seen answers but I don't understand how to make them work for my application.
I have a game that has a few view controllers: Welcome, Play, High Scores, Preferences and About. I don't have a navigation controller or a root controller of which I am aware. EDIT - I now have a rootview controller - I added [self.window setRootViewController:viewController];
to my appDelegate.m file
From the Welcome screen/viewcontroller I can go to the Play view controller, the about view controller, the high scores view controller or the prefs view controller. I would like to make whichever new controller I go to now be in charge, so that I can dismiss the Welcome view controller. In fact, any time I go to a view controller, I would like to be able to dismiss from memory any of the other view controllers - especially the one I just came from. I can go to most of the viewcontrollers from most of the viewcontrollers.
I go to the new view controllers using this:
- (IBAction)playGameAction:(id)sender {
FlipTestViewController *myViewController = [[FlipTestViewController alloc]
initWithNibName:@"FlipTestViewController" bundle:nil];
[UIView beginAnimations:@"flipview" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
forView:self.view cache:YES];
[self.view addSubview:myViewController.view];
[UIView commitAnimations];
}
What do I do to let the WeclomeViewController go, once I am safely in the FlipTestViewController (the play controller)? And how do I tell the new controller that it is now in charge and the others can go away? Am I even asking a question that makes sense? Please use small words and concrete examples when responding! Thank you!
On rdelmar's advice, I tried adding a call to change the RootvVewController into my button code - the code I use to bring up the new viewController:
- (IBAction)playGameAction:(id)sender {
FlipTestViewController *myViewController = [[FlipTestViewController alloc]
initWithNibName:@"FlipTestViewController"
bundle:nil];
[UIApplication sharedApplication].delegate.window.rootViewController = myViewController;
[UIView beginAnimations:@"flipview" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
forView:self.view cache:YES];
[self.view addSubview:myViewController.view];
[UIView commitAnimations];
}
Sure enough, then I look in the comments, the FlipTestViewController (my Play Controller) is the new RootViewController. Unfortunately, I get a blank white screen, no transition of any kind and log message telling me that my ViewDidDisappear in my FlipTestViewController is being called somehow. Probably because the Welcome Screen is still there somehow. Memory management problem perhaps? Ought I to take this to a new question?
I just changed the background color of the main.xib file and apparently that is the screen that is showing up (the blank white screen).
Upvotes: 3
Views: 6014
Reputation: 104082
It sounds like the easiest way to achieve what you want is to just reset the rootViewController property of the app's window. From anywhere in the app you can get a reference to the root view controller with [UIApplication sharedApplication].delegate.window.rootViewController. So, in whatever action method you're using to switch to the next view controller, you could alloc init that controller and then set the window's rootViewController property to that controller. If you keep no other reference to a controller, the old one should be deallocated when you reset the property (which may or may not be what you want -- you might want to have some properties that would keep track of the high score or where the player was in a game, for instance).
In the app delegate there is usually code something like this (when you start with a single view project):
WelcomeController *welcome = [[WelcomeController alloc] initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = welcome;
So I would put something like that in your app delegate with whatever view controller you want to show at start up. Then in your view controller code (or wherever your putting your buttons to switch view controllers) you would have something similar to (I used a segmented control in my test project):
-(IBAction)selectController:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 0) {
PlayViewController *player = [[PlayViewController alloc] initWithNibName:@"PlayViewController" bundle:nil];
[UIApplication sharedApplication].delegate.window.rootViewController = player;
}else{
HighScores *scorer = [[HighScores alloc] initWithNibName:@"HighScores" bundle:nil];
[UIApplication sharedApplication].delegate.window.rootViewController = scorer;
}
}
Upvotes: 1
Reputation: 28349
An easy approach would be to use a Navigation Controller. You can get the benefits of pushing/popping, which helps for sequences of screens.
You can then pop to a specific controller with:
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
This allows you to go to a specific view controller that has already been presented, without going through all the others.
Also, a bit less well known, you can just replace the entire stack of controllers with
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated
which also replaces the base controller with the controller at index zero.
So, you can easily get the top toolbar and all the nav controller functionality, and when you just want to reset everything to some single controller, you just do...
[navController setViewControllers:@[viewController] animated:YES];
EDIT
It sounds like you're not really sure what you want. Thus, you should give yourself some leeway, and not try to reinvent the wheel.
I think a navigation controller is the way to go. It already knows how to manage multiple controllers, and with setViewControllers
you can make it looks like you are just going from any controller to any other, but you get to keep the same nav controller as your main center of work.
Otherwise, you can still do all this yourself with
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
and
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
You can call them from your root view controller. When you want to change controllers, it will then just dismiss the current controller and present the new one.
Upvotes: 0
Reputation: 2501
To present a view controller modally, you might want to try this method:
- (IBAction)playGameAction:(id)sender {
FlipTestViewController *myViewController = [[FlipTestViewController alloc] initWithNibName:@"FlipTestViewController" bundle:nil];
myViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:myViewController animated:YES completion:nil];
}
This puts FlipTestViewController on top of the current view with a flip transition style.
Then to dismiss the view controller, you'd hook this up to a control (usually a button) in FlipTestViewController:
- (IBAction)dismissViewController:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
This dismisses the view controller with the same flip animation
Upvotes: 2