I needed to create an application base with multiple view
controllers, and an easy method for switching between them. I came up
with a solution that passes messages via the App Delegate, and has a
parent View Controller that manages the sub-views.
The following code is the App Delegate:
MultiviewAppDelegate.h
#import@class MultiviewViewController; @interface MultiviewAppDelegate : NSObject { UIWindow *window; MultiviewViewController *viewController; } @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet MultiviewViewController *viewController; -(void) displayView:(int)intNewView; @end
MultiviewAppDelegate.m
#import "MultiviewAppDelegate.h" #import "MultiviewViewController.h" @implementation MultiviewAppDelegate @synthesize window; @synthesize viewController; -(void) displayView:(int)intNewView { [viewController displayView:intNewView]; } - (void)applicationDidFinishLaunching:(UIApplication *)application { [window addSubview:viewController.view]; [window makeKeyAndVisible]; } - (void)dealloc { [viewController release]; [window release]; [super dealloc]; } @end
Pretty basic stuff (almost exactly the default for the AppDelegate
template). The only addition is the displayView function, which
passes a message to the parent View Controller.
MultiviewViewController.h
#import@interface MultiviewViewController : UIViewController { } - (void) displayView:(int)intNewView; @end
This has an internal displayView function which is called by the
AppDelegate.
MultiviewViewController.m
#import "MultiviewViewController.h" // you have to import the header files for // any views that this parent controls #import "View01.h" #import "View02.h" @implementation MultiviewViewController UIViewController *currentView; - (void) displayView:(int)intNewView { NSLog(@"%i", intNewView); [currentView.view removeFromSuperview]; [currentView release]; switch (intNewView) { case 1: currentView = [[View01 alloc] init]; break; case 2: currentView = [[View02 alloc] init]; break; } [self.view addSubview:currentView.view]; } - (void)viewDidLoad { // display Welcome screen currentView = [[View01 alloc] init]; [self.view addSubview:currentView.view]; [super viewDidLoad]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview // Release anything that's not essential, such as cached data } - (void)dealloc { [currentView release]; [super dealloc]; } @end
Now we just have to have multiple sub-views.
View01.h
#import@interface View01 : UIViewController { } @end
View01.m
#import "View01.h" #import "MultiviewAppDelegate.h" @implementation View01 - (void)goToTwo { MultiviewAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; [appDelegate displayView:2]; } - (void)viewDidLoad { NSLog(@"load01"); UIButton *btnOne = [UIButton buttonWithType:UIButtonTypeRoundedRect]; btnOne.frame = CGRectMake(40, 40, 240, 30); [btnOne setTitle:@"One!" forState:UIControlStateNormal]; [btnOne addTarget:self action:@selector(goToTwo) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btnOne]; [super viewDidLoad]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview // Release anything that's not essential, such as cached data } - (void)dealloc { NSLog(@"dealloc01"); [super dealloc]; } @end
The second view looks just like the first, but goes to “one”
instead of two.
View02.h
#import@interface View02 : UIViewController { } @end
View02.m
#import "View02.h" #import "MultiviewAppDelegate.h" @implementation View02 - (void)goToOne { MultiviewAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; [appDelegate displayView:1]; } - (void)viewDidLoad { NSLog(@"load02"); UIButton *btnTwo = [UIButton buttonWithType:UIButtonTypeRoundedRect]; btnTwo.frame = CGRectMake(40, 40, 240, 30); [btnTwo setTitle:@"Two!" forState:UIControlStateNormal]; [btnTwo addTarget:self action:@selector(goToOne) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btnTwo]; [super viewDidLoad]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview // Release anything that's not essential, such as cached data } - (void)dealloc { NSLog(@"dealloc02"); [super dealloc]; } @end
And that’s it! It seems like a lot, but it’s a basic framework that makes it easy to add in new views and navigate between them.
I created this to help me go between multiple screens built by different developers that weren’t working in the same environment. It makes it easy to add the .m and .h file of a View Controller, and then with some minor changes, be able to insert it into the navigation flow of any application.
One caveat: if you have a timer, you need to invalidate it before you call [appDelegate displayview:]. I’ve also been making it a habit to set my objAccelerator.delegate = nil in the dealloc function of each View Controller.
You must also have good memory management practices (release everything you alloc!), because the dealloc is not just called when the program terminates — it’s called every time you switch views.
Download the iphone multiview controller source code here!
Thanks for this solution, worked beautifully. One problem that I can’t seem to solve. The app works fine changing from landscape to portrait but if you start the app up with the phone in landscape it still starts up in portrait. Also, if you switch from one view to another while in landscape, the new views appear in portrait. Any ideas?
Just add:
currentView.view.frame = self.view.bounds;
after:
[self.view addSubview:currentView.view];
Thank you so much. Can you please help me by showing me that how i can switch between different NIB files using this framework. And i will switch using different buttons. Like if there are three views then there will be three button for each view named like view1, view2, view3. If i click from any view on view1 then view1.xib will be loaded and if i click from any view on view2 button then view2 will be loaded; in this way…
Here If i add any other XIB file then the program fails to run
Did your application fail even.,..after you linked the button event with IBAction method ?? I think that should have worked…
Could help to make a button that go back and forward between view
Hi
I want to create 6 buttons on the main screen through which the user can tap the button and can go any view to which he want and also that all 6 views will contain the same button for changing views and those 6 views contains different different info
How can I go please help
I am very new to this
Hi Sam,
You might want to consider using a Tab Bar Controller for what you’re describing:
http://www.iphonesdkarticles.com/2008/07/tab-bar-controller-tutorial.html
The project above does what you are describing (with two buttons, but six buttons and views could be created) but they would also have to be added to each of the views — which means if you wanted to change one (title, position, image, etc.) you’d have to do that for each of the views…
I copied the code but I just get a blank window on startup. Sorry if I’m missing something, I just started objective c.
Nevermind, i figured it out
hey Robby, i have the same problem, how did you fix it?
Pingback: Can’t call controller method from delegate | Technical support, Computer, programming issue, issue tracking, quality assurance
It’s pretty easy to call a method in my AppDelegate from anywhere in my code… but what about doing it the other way around?
From AppDelegate… I need to call 1 of the methods inside 1 of my views.
Hi Jeffrey,
I really don’t know how to say thank you enough. I downloaded your code for Framework for having Multiple Views in an iPhone app and it was so helpful. I needed a way to create a single app with five different views for a musical performance using 80 iPhones. I’ve tried for weeks to achieve this by dragging connections between objects in views and text files. Your code allowed me to just get on with it. The performance happens in November as part of the Space Time Concerto performance competition. You may like to watch the YouTube video I submitted. If you’re happy for me to do so I’d like to include your name among the acknowledgements when I update the site.
http://www.youtube.com/watch?v=gfaZly6dhQA&feature=related
Greg S
Excellent collection , and nice piece of explanation. Nice job