UIViewController in a UIView - iphone

Can I load a UiViewController in a UIView in another UIViewcontrller.
suppose UIViewControllerA has a UIView named subuiview. Can I load UIViewControllerB into subbuiview?
Thanks!

Starting with iOS 5
"Container view controllers" have been added in iOS 5. You can add a view controller as a child of another one with addChildViewController:.
You also are responsible for adding its view to its parent's view.
Everything is well documented in the iOS SDK documentation: Implementing a Custom Container View Controller.
To add a child view controller:
childViewController.frame = ...
[self.view addSubview:childViewController.view];
[self addChildViewController:childViewController];
[childViewController didMoveToParentViewController:self];
and to remove it:
[self willMoveToParentViewController:nil];
[self.view removeFromSuperview];
[self removeFromParentViewController];
Prior to iOS 5
It's possible to load another view controller and add its view as a subview of another controller's view.
UIViewController *subController = ...
[self.view addSubview:subController.view];
Although it's not recommended by Apple's guidelines:
Each custom view controller object you
create is responsible for managing all
of the views in a single view
hierarchy. [...] The one-to-one
correspondence between a view
controller and the views in its view
hierarchy is the key design
consideration. You should not use
multiple custom view controllers to
manage different portions of the same
view hierarchy.
(from the View Controller Programming Guide)
Your sub-controller won't receive rotation events, or viewWillAppear, viewWillDisappear, etc (except viewDidLoad).
So Apple advises us to use a single view controller managing the entire view hierarchy (but doesn't forbid to use multiple ones).
Each view may still be a custom subclass of UIView. Maybe you don't need another view controller but rather a custom view.

[self addSubview:viewControllerB.view];
try this in the sub view

It has always been problematic to simply use addSubview to add a view controller's view as a subview of another's. It's especially bad when people use it to transition between views, rather than relying upon other, more robust, solutions like presentViewController or pushViewController.
If you really want to add one view controller's view as a subview of another's, iOS5 introduced "view controller containment". Containment is discussed in the View Controller Programming Guide as well as WWDC 2011 session 102. Bottom line, you want to ensure you keep your view controller hierarchy synchronized with your view hierarchy, by calls to addChildViewController, didMoveToParentViewController, etc. See the documentation and the video for specifics.

Well you cant technically load a viewcontroller. You can load a viewcontroller's view as a subview of any view.
You need to also retain the view controller incase you have any actions attached to it. Otherwise it may result in crashes.
addsubview:controller.view is the method you want to look at.

Related

Added UIViewController in UIView giving trouble

I want to add a UIViewController class to an existing class as a subview, so i used the following code.
myEventsView = [[EventNameViewController alloc]initWithNibName:#"EventNameViewController" bundle:nil];
[myEventsView.view setFrame:CGRectMake(0, 39, 320, 400)];
[self.view addSubview:myEventsView.view];
It is added successfully but the problem is with button actions, those actions which have to navigate to other view controllers are not working. Those action methods are called, but action not performed, not getting why so, please guide for the above.
Thanks in advance.
Try
myEventsView = [[EventNameViewController alloc]initWithNibName:#"EventNameViewController" bundle:nil];
[myEventsView.view setFrame:CGRectMake(0, 39, 320, 400)];
[myEventsView willMoveToParentViewController:self];
[self.view addSubview:myEventsView.view];
[self addChildViewController:myEventsView];
[myEventsView didMoveToParentViewController:self];
From the docs:
Each custom view controller object you create is responsible for managing all of the views in a single view hierarchy.
What you are trying to do is to add one viewcontroller's view as a subview of another viewcontroller's view, hence mixing two view hierarchies. That will cause you problems as you have already experienced. Have a look at Carbon Emitter's Abusing UIViewCtrollers article, it gives a thorough explanation and an alternative.
Update
As suggested in the correct answer above, there exists a way to make one UIViewController act as a container for another. From Implementing a Container View Controller (UIViewController Class Reference):
A custom UIViewController subclass can also act as a container view controller. A container view controller manages the presentation of content of other view controllers it owns, also known as its child view controllers. A child’s view can be presented as-is or in conjunction with views owned by the container view controller.
However, this is an iOS >= 5 feature, so my answer will remain correct for applications running iOS versions < 5.
Muncken is right. You cannot add myEventsView.view as a subview to self.view, since myEventsView.view is controlled by its own view controller.
What you probably wanted to do is to add just an new view (that is not controlled by another view controller) as a subview to self.view. So, why don't you just instantiate such a view without a new view controller?

Call willrotate method for added subview controller

I have added one view controller to my first view controller as aa subview by using self.view add subview:secondview now when I'll rotate the device
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
method calls for only parent view Now I also want to call that method for child view controller so i can make required changes in child view controller also.
So for that what I have to do??
-Thanks in advance.
In WWDC 2011 Session 102 on view controller containment, they mention that a failure to keep one's view controller hierarchy synchronized with the view hierarchy can result in rotation events problems. They explicitly point out that if you just grab a view controller's view and add it as a subview of the main view, without adding the controller, itself, to the view controller hierarchy, you won't get these rotation events. In that WWDC session, they also suggest that if you want to "future-proof" your app, you'll want to manage view controllers properly.
From a pragmatic perspective, this means that as you go from one view to another, that you really should be transitioning the view controllers. Most commonly this means using pushViewController or presentViewControllerAnimated (formerly presentModalViewController). Or you can use view controller containment (see that WWDC session or look at the very brief comments about containment in the UIViewController Class Reference). But don't just grab the view from another view controller and just add it as a subview of the current view.
If you pursue view controller containment, at a minimum, you could add your child view's controller to the hierarchy via:
[self addChildViewController:childController];
[childController didMoveToParentViewController:self];

Managing multiple UIViews from one UIViewController

I'm getting confused on view controllers and would love a straight example. Here's the preamble:
I have a UIViewController with a matching .xib.
By default IB gives me a single View in the Document window.
I can make it appear by telling my UIWindow to addSubview:controller.view and bringSubviewToFront:controller.view
Here's the questions:
Should I add another View to the ViewController in IB? Or is there a better, programmatical way?
How do I tell the ViewController to switch between the Views?
From the ViewController downward, what does the code look like to achieve this?
I'm trying things but just making a mess so I thought I'd stop and ask...
Note that every button, label, image, etc. in your main view controller is actually a view in itself, however I've interpreted your question to mean that you want to manage multiple full-screen views or "screens". Each screen should have its own view controller to manage it. So to get the terminology right, a view-controller is an object that manages a single full-screen view (or almost full screen if it's nested inside a navigation controller or tab bar controller for example) and a view is the big area managed by the view controller as well as all the sub-views (images, buttons, labels, etc.) within it (they are all UIView sub-classes). The view controller manages all of them on that screen, if you want another screen/page then you should create a new view controller to manage it.
The root view controller (the one you add to the window) can be a plain old normal view controller that you've designed in IB, however it's probably more useful if you use a navigation controller or a tab bar controller and add your designed view controller to that - then you can push additional view controllers as needed.
Another way (if you don't want navigation or tab-bar style) would be to transition to other view controllers directly in the main window using whatever transitions you like (or just replace the old one). We'll leave that for now though.
Any sub-views of your main view controller (the one you've designed in IB) will be automatically loaded from the nib file, but you can also add your own views programatically if you want (typically you would use one or the other, i.e. nibs or programatically, but you can mix and match if you want). To do it programatically, override loadView in the view controller and then call [super loadView]; then do [self.view addSubView:myOtherView]; (create the myOtherView first of course). Note that the first time .view is accessed on your view controller, it actually calls loadView to create the view, so inside loadView it's important to call [super loadView]; before trying to access self.view :D
To switch between views, using the navigation or tab bar controllers makes it very easy. So put your main view controller inside (for example) a navigation controller and put the navigation controller in the window, so you've got window->navigationController->myController. Then from an action method in your view controller (you can hook up the action methods in IB), for example when an "about" button is pressed do this:
- (void)doAbout
{
// Create the about view controller
AboutViewController* aboutVC = [AboutViewController new];
// Push the view controller onto the navigation stack
[self.navigationController pushViewController:aboutVC animated:YES];
[aboutVC release];
}
Note that the about view controller is created programatically here - if your about view is designed in IB then instead use initWithNibName:bundle: to create it.
And that's how you manage multiple screens.

Iterating 'Active' View Controllers

Ola Folks,
In an iPhone application I am displaying different views by using the addSubView:SomeViewController.view method.
I want to be able to, at the very least, log the view controllers that are in the view hierarchy that is being displayed. I would prefer to be able to get a handle to a specific view controller.
I know how to iterate the views, I just do not see how to access the view controllers of those views. I am looking for something that will give me the type of access to the view controllers that UINavigationController::ViewControllers does.
I thought I could get away with:
for (UIViewController* oVC in [self.view subviews])
but this is not having the intended effect.
If someone has a way of doing this, please share it with me.
-isdi-
A view doesn't keep a reference to its view controller (or know anything about view controllers in general), so you'll have to keep track of that mapping yourself. If you keep all of your view controllers in an array viewControllers, you could do something like:
- (UIViewController *) viewControllerForView:(UIView *)view {
for (UIViewController *viewController in viewControllers)
if (viewController.view == view)
return viewController;
return nil;
}
The standard way for a view to interact with the view controller that owns it is by having the view controller set as the delegate or action target of the view. The view is designed not to have any details about the delegate or action target.
If you have implemented your own view, just add a member to hold a reference to the view controller. Or adopt a delegate model for the view so that it does not matter what class the delegate is.
If you are treating the views as a stack and want to maintain a stack of view controllers along side it, similar to what UINavigationController does for you, you must do so manually. Couple every call of addSubview:viewController.view with a call to [myViewControllerArray addObject:viewController] and remove the viewController form the array when the view is removed from the view hierarchy.

What causes a UIViewController to become active?

I am sure this is an easy question, but one that has escaped me for some time now.
Say I have a UIViewController, either defined as a root in an XIB or on a stack. At some point in my code I want to replace it with another view controller. Just flat out replace it. How would I do that?
I have tried defining the controller and assigning, but not sure what actually makes it push on the screen with the absence of a navigation controller.
I think when you say that you want to replace the view controller, what you actually mean is that you want to replace the view. Bear in mind that view controllers aren't visible, but every view controller maps to a view, which can become visible by getting added as a subview of a visible view.
Your solution of replacing self.view with the new view controller's view may work in your particular case, but it's probably not the "correct" answer to your question. There are going to be cases where this solution won't work for you.
Let's say you have a simple view based application with no navigation controller and no tab bar controller. In your app delegate you construct an instance of YourFirstViewController, and you call [window addSubview:yourFirstController];. Your view hierarchy now consists of a UIWindow with a single subview -- the view for YourFirstViewController.
Now let's say the user presses a button on that view, which is handled by an IBAction defined in YourFirstViewController. You want to respond by "replacing" YourFirstViewController's view with a view associated with YourSecondViewController. I put "replacing" in quotes because we more commonly present a view by pushing its view controller onto a navigation stack, or calling presentModalViewController:animated: to present the view modally, but let's assume that you've rejected those options for some reason, and you actually do want to manually replace YourFirstViewController's view with YourSecondViewController's view.
This is a simple matter of manipulating the view hierarchy. You want to remove YourFirstViewController's view from its superview (the UIWindow in this case), and you want to add YourSecondViewController's view as a subview to replace it. Your action would therefore look something like this:
- (IBAction)replaceButtonClicked {
UIView *mySuperview = self.view.superview;
YourSecondViewController *secondController = [[YourSecondViewController alloc] init];
[mySuperview addSubview:secondController.view];
[self.view removeFromSuperview];
[secondController release];
}
When we use a methods like -pushViewController:animated: or -presentModalViewController, the receiving controller manipulates the view hierarchy for us. This may make it seem like we're looking at view controllers on the screen, but we're not. We're just looking at a big hierarchy of nested views going all the way up to a UIWindow at the top.
You can present a new view controller modally:
[self presentModalViewController:aViewController animated:YES];
This won't outright replace the current VC, but it will display a new view over the current view.