Is it possible to create multiple view or window in a (Window based) iPhone app?
Yes kind of possible. Just create a new view using a view controller and create an instance of that view in your class. Then in an ibaction you could do some removing and adding subviews. That's just a quick and easy way tho, you can get into a lot more detail with how you would manage each view, etc.
Edit on Request:
In your class, you would create an instance of it in the interface like so:
MyClass *myClass; (make sure to alloc and init in the init or awakeFromNib method)
Then make an instance of the app delegate in the ibaction like this:
MyAppDelegate *myAppDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
And then you can do this to switch from one view to another:
[self removeFromSuperView]; (or self.view in case this is a view controller)
[[myAppDelegate window] addSubview:myClass];
You can do something like the following to add a view programatically:
//If you create controllers via XCode, just link them in the .h file with IBOutlet
UIViewController *aViewController = [[UIViewController alloc] initWithNibName:#"YourNibName" bundle:[NSBundle mainBundle]];
self.viewController = aViewController;
[aViewController release];
// Add the view controller's view as a subview of the window
UIView *controllersView = [viewController view];
[window addSubview:controllersView];
[window makeKeyAndVisible];
Related
I've been receiving a warning that is related to my use of the GKTurnBasedMatchmakerViewController and the BannerViewController for iAd. That warning is:
Presenting view controllers on detached view controllers is discouraged <RootViewController: 0x14cd143c0>
What is wrong with the sequence of code shown below that causes this warning?
In AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *viewController;
}
In AppDelegate.m
- (void) applicationDidFinishLaunching:(UIApplication*)application {
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
[window setRootViewController:viewController];
[window addSubview: viewController.view];
}
Then when the user presses a Play button on my home screen, I first open the game center view controller as follows (notice the 2nd line is setting presentingViewController equal to the rootViewController that was set up in the appDelegate):
AppDelegate * theAppDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
self.presentingViewController = theAppDelegate.viewController;
GKTurnBasedMatchmakerViewController *mmvc = [[GKTurnBasedMatchmakerViewController alloc] initWithMatchRequest:request];
[presentingViewController presentViewController: mmvc animated: YES completion:nil];
After the above code runs, a new scene is loaded. This scene is described in my GameSelectionLayer.h as follows:
#interface GameSelectionLayer : CCLayer <InAppStoreControlLayerDelegate> {
...
RootViewController *viewController;
AppDelegate *app;
BannerViewController *bannerViewController;
}
Then in my GameSelectionLayer.mm, I load the bannerViewController onEnter as follows:
-(void)onEnter {
[super onEnter];
app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
viewController = [(AppDelegate *)[[UIApplication sharedApplication] delegate] viewController];
bannerViewController = [[BannerViewController alloc] initWithContentViewController:viewController];
app.window.rootViewController = bannerViewController;
}
I receive the above mentioned warning when the above code runs. Please let me know what you think I might be doing wrong that is causing this warning.
The problem is you are replacing the view hierarchy of a view controller which has another view controller presented. The "detached" warning comes when you try to present a view controller from a view controller which is not attached to a window, or does not have a descendent view controller attached to a window.
Here I recommend two approaches. Either dismiss all view controllers before replacing the root view controller, or, the better of the two options, use another window with its own root view controller hierarchy.
Also, note that you should not add the view controller's view as a subview of the window. The system does it for you when you set the view controller as the root view controller.
I have a custom view controller named CKCalendarViewControllerInternal.
CKCalendarViewControllerInternal
This class is the subclass of UIViewController.
CkCalendarViewController
I have a custom view controller named CKCalendarViewController. It's a subclass of UINavigationController as follow:
#interface CKCalendarViewController : UINavigationController <CKCalendarViewDelegate, UINavigationControllerDelegate>
This class is initialize with the CKCalendarViewControllerInternal as follow:
- (id)init
{
CKCalendarViewControllerInternal *calendarViewController = [CKCalendarViewControllerInternal new];
self = [super initWithRootViewController:calendarViewController];
}
Now, In AppDelegate my first view is as follow:
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.viewController = [[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil] autorelease];
UINavigationController *n1=[[UINavigationController alloc]init];
n1.viewControllers=[[NSArray alloc]initWithObjects:self.viewController, nil];
self.window.rootViewController=n1;
[self.window makeKeyAndVisible];
return YES;
}
CkDemoViewController
This class is the subclass of CkCalendarViewController as follow
#interface CKDemoViewController : CKCalendarViewController
ViewController.m
When i try to push the CKDemoViewController on button clicked.
Error & Question
It shows me error like
Exception: Pushing a navigation controller is not supported
Exception: [NSException]:Pushing a navigation controller is not supported
ex.name:'NSInvalidArgumentException'
ex.reason:'Pushing a navigation controller is not supported'
Reason for error
This is because the CKCalendarViewController is the subclass of UINavigationController.
If i try to open the modal view, it works perfectly.
But How can i initialize the CKCalendarViewController as shown above with the CKCalendarViewControllerInternal class??
Thank you,
Answer will greatly appreciate
If I understand correctly what you are doing, the simplest "hackish" way to make things work would be making CKCalendarViewController derive from CKCalendarViewControllerInternal. I am suggesting this because I see that you are trying to use your CKCalendarViewController as a normal view controller, so there should be no reason to have it be a navigation controller.
Another possibility would be for you to actually use your CKCalendarViewController as a navigation controller by doing this in your app delegate:
UINavigationController *n1 = [[CKCalendarViewController alloc]init];
n1.viewControllers = [[NSArray alloc]initWithObjects:self.viewController, nil];
self.window.rootViewController = n1;
but this depends on what you are trying to achieve.
More generally, if you are interested in "nesting" controllers within controllers, you should learn about controller containment. In controller containment, what you do to add a controller to another one is basically this:
[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];
I have a main view controller and am presenting a child view. For one of the settings inside the child, I need to call the main view controller again. It would just make things a lot easier.
The following causes a hierarchy problem:
#define appDelegate (MyAppDelegate *)[[UIApplication sharedApplication] delegate]
[self presentViewController:[appDelegate mainViewController] animated:YES completion:^{}];
Is there any way to call the mainViewController easily while not losing the state of the child view?
EDIT
Here is how I'm presenting the child view.
ChildViewController *childViewController = [[ChildViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:childViewController];
[childViewController release];
[self presentModalViewController:navigationController animated:NO];
[navigationController release];
You can't present a view controller that has already been presented or is in a navigation stack. What is the mainViewController? Did you instantiate it? Has it been added to the screen yet?
If yes to both, you either need to back into it (dismiss to it) or remove it from it's parent first and then present it.
In your child view, you should have access to your application delegate and its mainViewController property, like this:
MyApplicationDelegate *appDelegate = (MyApplicationDelegate *)[[UIApplication sharedApplication] delegate];
I have a view-based application with three xib files, each with its own view controllers. How do I change from one to another? I use this to move from xib 1 to xib 2, but when I use the same code to move from xib 2 to xib 1, i get a EXC_BAD_ACCESS on the [self presentModal....] line.
MapView *controller = [[MapView alloc] initWithNibName:#"MapView" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
How can I freely move from one xib to another?
What I think you are trying to do is is present a modal view and then dismiss it, right? If that is the case then you put the code below in the method that you use to dismiss it(e.g. -(IBAction)dissmissModalView)
[self.parentViewController dismissModalViewControllerAnimated:YES];
Hopefully that works. Let me know.
initWithNibName isn't really necessary... you can change that to nil.
So, here is the correct code (without animation):
MapView *mapView = [[MapView alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:mapView animated:NO];
You should not be receiving EXC_BAD_ACCESS when trying to go back to view 1 using present. If you cannot resolve it, just use this instead:
[self dismissModalViewControllerAnimated:YES];
The second view controller will disappear and the first view controller will be visible again.
Note that presenting modal view controllers like the other answers here will mean that you have an ever-accumulating stack of view controllers. Use the application long enough and it will crash.
Instead, you can swap out the view from the application's window. Here's one way of doing that:
Add a data member to your app delegate to store the current view:
#class MyAppDelegate : NSObject <...>
{
UIViewController* currentVC;
}
and add a message there to swap VCs:
-(void)setCurrentVC:(UIViewController*)newVC
{
if (newVC==currentVC) return;
if (currentVC!=nil)
[currentVC.view removeFromSuperview];
currentVC = newVC;
if (newVC!=nil)
[self.window addSubview:newVC.view];
}
and to swap from one screen to another:
MapView* mapView = [[MapView alloc] init];
[[[UIApplication shared] delegate] setCurrentVC:mapView];
I am working on an iPhone app but found that I require another view / window to get the user to input and save data / information there.
How do I add another view? Do I add it in interface builder and then link it in the main app delegate or will it have its own .h and .m files.
I selected a window view app to start with, do I need to start over with a flip side view app or can this just be added in anyway if I have the correct code there.
manny thanks
Carl
The Window app is perfect for you. In your AppDelegate file, you should have a section like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
// Configure and show the window
[window addSubview:[yourViewController view]];
[window makeKeyAndVisible];
}
This is the part of the code that declares, allocates and adds your custom view to the window. You have a couple choices for how to add the second view. You can either add it in place of this one, or add it after this one using a Navigation Controller. To add the navigation controller, change the above method to look like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
UINavigationController *yourViewControllerWrapper = [[UINavigationController alloc] initWithRootViewController: yourViewController];
// Configure and show the window
[window addSubview:[yourViewControllerWrapper view]];
[window makeKeyAndVisible];
}
There, we create your custom view, then wrap it in a navigation controller. The navigation controller is what gets added to the window. Next the code to switch to the second view would look like this, assuming you switch views on a button press:
-(IBAction)switchViewController{
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController];
}
Of course, you should replace the line
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
with the proper way of instantiating your second view controller. This could be from a nib file like above, or programmatically.
As far as creating the view files, you should create a nib in Interface builder for the layout of everything, then create a .h and .m file for the ViewController code itself.
you can also display new frame instead of new view. It is easier sometimes, as you don;t have to pass parameters - you are in one class:
CGRect frame = okresView.frame;
frame.origin.x = frame.size.width;
if ( [okresView superview] == nil )
{
[self.view addSubview:okresView];
}
okresView.frame = frame;
[okresDataTableView reloadData]; // przeĊadowanie tabeli na subwidoku
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.5];
frame.origin.x = 0;
okresView.frame = frame;
[UIView commitAnimations];
if you want new subview, you can use a few methods - just download few applications from XCode help and check how they do this. Nice example are in 'Elements' and 'UICatalog' application where you have flipped view and other examples.
// Create and push another view controller.
UIViewController *myViewController = [[UIViewController alloc] init];
myViewController.title = #"My First View";
myViewController.view.backgroundColor = [UIColor redColor];
//to push the UIView.
[self.navigationController pushViewController:myViewController animated:YES];