I've made a custom view to which I add a custom button. This custom view goes as a subview to yet another view (Kal calendar for iphone) that I push into a navigation controller. Now the button in my custom view is connected to an IBAction in which I am not able to call upon the self.navigationController to pop the current view from.
I've tried the [[sender superview] navigationController] for a hierarchy of superview calls but it doesn't work that way either.
Any ideas please?
Thanks
A view typically has no knowledge of its view controller (and consequently, to its or its superview's view controller's navigation controller) because this would introduce a tight coupling between view and view controller that is usually unwanted and unnecessary.
The easiest way to solve your problem would be to have the view controller instead of the view handle the button's action. If that doesn't work for your design, consider designing a delegate protocol for your custom view and make your view controller the custom view's delegate. The view would then call the delegate method in the button's action method. This latter method is used a lot throughout Cocoa, e.g. by UIScrollView (UIScrollViewDelegate) and UITableView (UITableViewDelegate).
Related
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];
I have a UIViewController's view inside my UIScrollView subclass. The problem is my UIViewController is not getting the willRotate delegate called when I rotate the device. This is probably because UIView does not have a rotation delegate implemented in it. What is the best way to solve this?
Basically the structure is I have a MainViewController in which it has a UIScrollView. Inside this UIScrollView I have a subviews, which is the view of a bunch of UIViewControllers. The issue now is, it's not getting rotation calls when I rotate. One way to deal with this is to delegate from the MainViewController to those respective UIViewController. Is there a better/elegant way to solve this?
I am adding it as a subview from my UIScrollView not my MainViewController and you can't do UIViewControllers containment from a UIView. Correct me if I am wrong
I think you're going against the MVC pattern. You can't have a controller inside a view; instead you should have a controller that mediates the communictaion between the view and the user's input. In your case you could set the scrollview as self.view of the MainViewController, and then add the viewcontrollers views as subviews.
Watch the video that I posted in my comment: https://developer.apple.com/videos/wwdc/2011/?id=102
Here is a short summary of view controller containment, which is the design you are looking for, not combining all your logic into one view controller or using delegation for something that is built into the SDK.
A view controller has a view and provides logic for that view and most likely some of it's subviews.
You might have a complex view hierarchy and complex logic for specific views in that hierarchy that warrant the view to have it's own view controller controlling it and it's subviews.
Say you have a MainViewController and it's view is a UIScrollView (or subclass). Inside that scrollview, you might have an assortment of complex views that warrant their own controller, so you have a class, SubViewController that has the subview of the scrollview as it's view.
SubViewController needs to have rotation and appearance method callbacks working correctly in order to implement your logic for the the subview and handle layout changes.
[mainViewControllerInstance addChildViewController:subViewControllerInstance];
But, wait. The subview is still not in the view hierarchy.
[mainViewControllerInstance.view addSubView:subViewControllerInstance.view];
You have successfully created a valid view controller hierarchy of two view controllers and set up the associated view hierarchy of their views.
You will now have the appropriate callbacks functioning, as MainViewController will forward them to SubViewController.
EDIT:
See the documentation for an over view of view controller containment: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
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.
i have an app that uses a navbar. What i want to acomplish is make it transparent when i push in the last view from the nav sequence, and make it opaque when i click the back button on the nav
i tried with on dealoc, but it doesn't work. My view is an UIScrollView not an UiView, but i guess that makes no difference.
As i see it, eighter i have to control the events on the nav bar, and see the type of the view with a loop or trigger some event on the "unloading" of my current view
when i push in the view i do a
self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
and when it pops out i need the
self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
Pushing and popping a view with UINavigationController or UITabController will call the view
{Will,Did}{Appear,Disappear} methods so I think you need to hook into the child view's ViewWillDisappear.
I'd architect it so that top level navigation controller sets itself as the childs delegate, and the child calls its delgate with an "I'm unloading" type function where you change the navbar style.
Actually the best way for this is to use UINavigationControllerDelegate. I extended UINAvigationController and set the delegate to self and used one of the methods of the UINavigationControllerDelegate protocol.
You can't really depend on dealloc to ever get called, much less when you want it. That should only be used to release retained objects.
I think you should be able to add the barStyle changes in the viewDidAppear and viewDidUDisappear methods of your view controller.
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.