View Controllers: How to switch between views programmatically?

IphoneUikitUiviewcontrollerUitabbarcontroller

Iphone Problem Overview


In short: I want to have two fullscreen views, where I can switch between view A and view B. I know I could just use an Tab Bar Controller, but I dont want to. I want to see how this is done by hand, for learning what's going on under the hood.

I have an UIViewController that acts as an root controller:

@interface MyRootController : UIViewController {
	IBOutlet UIView *contentView;
}
@property(nonatomic, retain) UIView *contentView;

@end

The contentView is hooked up to an UIView which I added as an subview to the "view" of the Nib. This has green color and I see it fullscreen. Works fine.

Then, I created two other View Controllers pretty much the same way. ViewControllerA and ViewControllerB. ViewControllerA has a blue background, ViewControllerB has a black background. Just to see which one is active.

So, in the implementation of myRootController, I do this:

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    ViewControllerA *vcA = [[ViewControllerA alloc] initWithNib];
    [self.contentView addSubview:vcA.view];

    [cvA release];
}

By the way, the -initWithNib method looks like this:

- (id)initWithNib { // Load the view nib
	if (self = [super initWithNibName:@"ViewA" bundle:nil]) {
		// do ivar initialization here, if needed
	}
	return self;
}

That works. I see the view from ViewControllerA when I start the app. But now the big question is: A View Controller typically has all those methods like:

  • (void)viewWillAppear:(BOOL)animated;
  • (void)viewDidDisappear:(BOOL)animated;
  • (void)viewDidLoad;

...and so on. Who or what, or how would those methods be called if I do it "my" way without a tab bar controller? I mean: If I allocate that ViewController's class and the view get's visible, would I have to take care about calling those methods? How does it know that viewWillAppear, viewDidDisappear, or viewDidLoad? I believe that the Tab Bar Controller has all this "cleverness" under the hood. Or am I wrong?

UPDATE: I've tested it. If I release the view controller (for example: ViewControllerA), I will get no log message on viewDidDisappear. Only when allocating and initializing the ViewControllerA, I get an viewDidLoad. But that's it. So all signs stand for the cleverness of UITabBarController now ;) and I have to figure out how to replicate that, right?

Iphone Solutions


Solution 1 - Iphone

There's a nice example of switching views in Chapter 6 of Beginning iPhone Development. You can see the source code for it here: http://iphonedevbook.com/

SwitchViewController has the code to change views programatically.







(IBAction)switchViews:(id)sender
{




if (self.yellowViewController == nil)
{
YellowViewController *yellowController = [[YellowViewController alloc]
initWithNibName:@"YellowView" bundle:nil];
self.yellowViewController = yellowController;
[yellowController release];
}




[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];




UIViewController *coming = nil;
UIViewController *going = nil;
UIViewAnimationTransition transition;




if (self.blueViewController.view.superview == nil)
{
coming = blueViewController;
going = yellowViewController;
transition = UIViewAnimationTransitionFlipFromLeft;
}
else
{
coming = yellowViewController;
going = blueViewController;
transition = UIViewAnimationTransitionFlipFromRight;
}




[UIView setAnimationTransition: transition forView:self.view cache:YES];
[coming viewWillAppear:YES];
[going viewWillDisappear:YES];
[going.view removeFromSuperview];
[self.view insertSubview: coming.view atIndex:0];
[going viewDidDisappear:YES];
[coming viewDidAppear:YES];




[UIView commitAnimations];







}

}

Solution 2 - Iphone

You can begin from the simplest removeFromSuperview/insertSubview and add code to it little by little.


//SwitchViewController.h
#import 
@class BlueViewController;
@class YellowViewController;




@interface SwitchViewController : UIViewController {
IBOutlet BlueViewController *blueViewController;
IBOutlet YellowViewController *yellowViewController;
}




(IBAction)switchViews:(id)sender;
@property (nonatomic, retain) BlueViewController *blueViewController;
@property (nonatomic, retain) YellowViewController *yellowViewController;
@end
  • (IBAction)switchViews:(id)sender; @property (nonatomic, retain) BlueViewController *blueViewController; @property (nonatomic, retain) YellowViewController *yellowViewController; @end


//1. remove yellow view and insert blue view




(IBAction)switchViews:(id)sender {
if(self.blueViewController.view.superview == nil)
{
[yellowViewController.view removeFromSuperview];
[self.view insertSubview:blueViewController.view atIndex:0];
}
}




//2. appear=insert, disappear=remove
if(blueViewController.view.superview == nil)
{
[blueViewController viewWillAppear:YES];
[yellowViewController viewWillDisappear:YES];



[yellowViewController.view removeFromSuperview];
[self.view insertSubview:self.blueViewController.view atIndex:0];

[yellowViewController viewDidDisappear:YES];
[blueViewController viewDidAppear:YES];




}




//3. now add animation
[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
//blue view will appear by flipping from right
if(blueViewController.view.superview == nil)
{
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight
forView:self.view cache:YES];



[blueViewController viewWillAppear:YES];
[yellowViewController viewWillDisappear:YES];
	
[yellowViewController.view removeFromSuperview];
[self.view insertSubview:self.blueViewController.view atIndex:0];
	
[yellowViewController viewDidDisappear:YES];
[blueViewController viewDidAppear:YES];




}
[UIView commitAnimations];


Solution 3 - Iphone

If I understand correctly, what you are trying to accomplish is pretty straightforward.

Just add a UINavigationController on your application delegate and do:

[navigationController pushView:vcA];

Delegates will be called accordingly:

  • (void)viewWillAppear:(BOOL)animated;
  • (void)viewDidDisappear:(BOOL)animated;
  • (void)viewDidLoad;

And when you want to pop the view and push another one:

[navigationController popViewControllerAnimated:true];
[navigationController pushView:vcB];

If you don't want the navigationController showing just use:

[navigationBar setHidden:YES];

Where navigationBar is the UINavigationBar corresponding to your UINavigationController.

Solution 4 - Iphone

This may be an old issue, but I recently came across the same problem and had a hard time finding something that worked. I wanted to switch between two complementary view controllers, but I wanted the switch to be animated (built in animations work fine), and I wanted it to be compatible with storyboards if possible.

For taking advantage of built-in transition, UIView's +transitionFromView:toView:duration:options:completion: method works beautifully. But, it only transitions between views, not view controllers.

For the transition to be between whole view controllers, not just views, creating a custom UIStoryboardSegue is the way to go. Whether or not you use storyboards, this approach lets you encapsulate the whole transition and manage the passing of relevant information from one view controller to the next. It only involves subclassing UIStoryboardSegue and overriding a single method, -perform.

For a reference implementation, see RAFlipReplaceSegue, the exact custom segue I put together using this approach. As a bonus, it also replaces the old view controller with the new if it is in a UINavigationController stack.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThanksView Question on Stackoverflow
Solution 1 - Iphonenevan kingView Answer on Stackoverflow
Solution 2 - IphoneChilly ZhongView Answer on Stackoverflow
Solution 3 - IphonePablo Santa CruzView Answer on Stackoverflow
Solution 4 - IphoneRyan ArteconaView Answer on Stackoverflow