What I want to achieve:
when the user presses a button in the view controller in the container view I want it to be able to access and change a property of the super view of which the container view is a subview in.
Is this possible? I have seen a lot of questions about the super view being able to access the subview's properties but I would really like for the container view to be able to access the superview's property.
Use property parentViewController as self.parentViewController and access all the properties you want.
Actually, what you are trying to do is wrong from architectural point of view. When a parent has an access to child is ok, when child has an access to parent — not ok. You break a modular structure of your app. You cannot reuse your views after that.
Related
I'm trying to create a custom container view controller. I want to use the standard ViewControllerTransitioning pattern for animating the addition of child views, but I'm a bit stuck. I'm writing this container view controller completely in code, as the number of child view controllers can vary.
I've already looked at this tutorial and it has helped me very much, but I can't figure out this step.
The flow of adding a new child view controller is currently like this:
'MyContainerVc'.addNewSubViewController
Call UIViewController.addChildViewController
Create transitioning context
Fetch animator
Animate
'Container View'.addSubview
Create autolayout positioning/height constraints
The positioning/height constraints can be created (and are) in the container view, as the container view controller does not need to control them, but the width constraint needs to be created in the container view controller, as the child vcs can specify a preferredContentSize.width to my container vc. The container vc will try to respect the child vcs' preferences as much as possible and base the width constraints on it as much as possible.
I'm not sure when the constraint for the width of the subviews can be created. The constraint needs to be enforced before the animation is performed, as the width should be defined before the child view appears. However, I cannot activate it before the child view has been added as a subview and if I activate it after the animation has completed, the width is not defined properly during the animation.
The animator should only use the transitioningContext and use the addSubview method of the container view, as it should be agnostic to what kind of transition it is animating.
Also, is creating the AutoLayout constraints in addSubview the best way to go or should it be done somewhere else, e.g. in didAddSubview?
Some advice is very appreciated!
I think I figured it out. I'm going to create a delegate protocol that specifies a function that tells the container view controller to create the width constraint and I'll call that method in addSubview of the container view.
I have an iOS project where I have my main view Controller, A, and another ViewController B. B is embedded in A as a child view controller. The whole thing is set up in Interface Builder using a Container View.
Now, B has some logic where it reacts to pan gestures to resize its view. This all works fine, the problem is that the Container View always stays the same size and does not resize with B's root view. I want the Container View's size to stay in sync with the root view of B.
What is the best approach for this? Is there any way to set this up in Interface Builder? The only feasible solution I found so far was to create a BDelegate, which A listens to and then resizes the Container View. Is there an easier way to achieve this?
thanks
Thanks to your answers, I got pointed in the right direction - specifically, that this is not possible the way I thought it was.
There is no way to have constraints between the views of a parent view controller and a child view controller - neither in IB, nor in code
As far as I can see, there are two ways to solve this:
Don't use a second UIViewController. Make the root view of your child view controller an actual subview of yourself, and just have a single UIViewController.
Do not use auto layout. Manage the frame of your child view controller's view manually, and have delegate callbacks back to your parent view controller where necessary. In those delegate callbacks, your parent view controller can react to size changes of the child view controller's view.
equalHeight and equalWidth constraints should solve your problem
So here is the problem I am trying to solve.
In each viewController I am trying to insert ads and the actual control elements. I finished couple of tutorial on raywenderlinch.com to understand that how people professionally put ads in their app. They used UIViews to have two views under mainview of view controller. So I completely understood that one subview hold the ads and another is holding actual app contents. if Ad is loaded take up the screen or else let other view have all available area.
After I came back to xcode I started coding the way I learned there. but when I was dropping UIView on storyboard, I saw containerView, which I think was not present when the tutorial was written.
So I am here to ask about the both approach and their pros and cons.
So basically its UIView vs ContainerView. Which way I should do, and why ?
Any help would be greatly appreciated.
You use UIView when you already have a view and you do not need to have a dedicated view controller to build and handle interactions within it.
From the UIView help page:
UIView object claims a rectangular region of its enclosing superview (its parent in the view hierarchy) and is responsible for all drawing in that region ...
Simplified structure:
YourViewController ---(has)---> UIView
You use UIContainerView when you need to embed another view controller in the one that you already have. The embedded view controller is in charge of returning a view for the region that the UIViewContainer occupies. Therefore, your UIContainerView knows which view controller to use to render UIView inside the region it occupies.
From the UIContainerView help page:
Container View defines a region within a view controller's view subgraph that can include a child view controller.
Simplified structure:
YourViewController ---(has)---> SubViewController ---(has)---> UIView
That SubViewController returns a view and handles its events.
As an alternative answer, you can also consider the use case instead of the technical differences. For example: Why use a container view?
A common use for container views is to reuse (share) a view, directly in the storyboard. Previously, reusing a view required creating a separate "xib" file, and programmatically adding that view when the view controller was loaded.
The above image is from this extremely simple, easy to follow guide that walks you through how to setup a container view that is shared between 2+ view controllers.
A few other thoughts on when to use it:
A navigation bar is part of a UINavigationController, which is a container view controller. So, if you wanted to build a custom alternative, you'd probably use a container view.
A container might help anytime that you want to temporarily show a complex view on top of your current VC but can't/don't want to present another VC modally. This approach still allows you to build that temporary view in interface builder, to setup auto layout constraints for it, etc
I also found a guide explaining that there's a way to switch out different container views based on the situation, allowing your VC to have sub-sections which are very dynamic, yet without having to build those sub-sections programmatically. A picture, from that guide, exhibiting what I'm referring to:
Hopefully this helps people who are trying to figure out when a container view applies to them. If you have other example use cases, please edit/add them or leave them in the comments!
If you see in detail these container view of UIView class type. To get the insights of why we need containerView you should see below portion
In most ways, a container view controller is just like a content view controller. It manages views and content, coordinates with other objects in your app, and responds to events in the responder chain. Before designing a container controller, you should already be familiar with designing content view controllers. The design questions in “Creating Custom Content View Controllers” also apply when creating containers.
for more detail about container view goto link
But before you begin you should have an understanding of
and also you can check this tutorial for how to use container view.
Thus you can go for both the approaches.
Hope this will help you. happy coding :)
I have a UIScrollView in my app and I am adding some custom views from xib to it so you can horizontally scroll (tabbing) in ScrollView to change which one is shown. For now this works but I have a problem with connecting views to controllers.
I don't know how to choose structure of ViewControllers (how many controllers should I use, use nested controllers,...).
I have a rootView and its controller. In this rootView there is a ScrollView and this ScrollView contains some custom views (subviews) loaded from xib (using loadNibNamed method).
My question is should I use the same ViewController as for rootView also for these subviews in ScrollView? Problem is that the ViewControllers view property is already bind to the rootView (super view in rootView) so when I bind this view property also to subviews an error is occurred. Also if I create new controller for these subviews an error is occurred as well.
When I am loading subviews to the ScrollView with loadNibNamed method in ViewController of rootView, owner of these subviews is ViewController (owner argument of loadNibNamed method is set to self).
Can you tell me please, how should I solve this? What controller should I use for subviews, should I create new one or should I use existing one. Or should I use some nested controller? I am newbie in iOS development so I have a chaos in using ViewControllers right now...
If there isn't much code that is relative to controlling the sub views you could use just the root view controller. i.e A single controller for a single scene would be a good MVC approach.
If you are using it this way , don't change the view property of view controller as this messes it up for the root view - controller setup. If you just need a reference to this views you already have it with the return value of loadNibNamed. Also if you are setting the owner to self then create additional instance variable to hold the sub views(and not the view property) so that you can specify the owner from the xib itself and connect the references appropriately.
However if you have substantial business logic to be written regarding the sub views then its fine to create separate view-controllers(a single class would be fine if all the subviews behave the more or less same way if you are getting what i mean) for it. In the xib for the subviews, you can specify this class as the owner and when using loadNibNamed: you should create an object of the subviewcontroller class and specify this as the owner. This way you can modularize the whole thing.
I have a Container View that holds 1 of 3 view controllers swapped out by 3 tabs (across the bottom).
Here's my Storyboard:
I'm taking this approach so that I can have custom tabs and a single Save button for all the fields in this big form.
How can I access the IBOutlets in those 3 child view controllers from inside my Entry Detail View Controller class?
Here's what I've done to try and access it in the parent.
//EntryFlightInfoViewController.h (Child 1)
#property (strong, nonatomic) IBOutlet UITextField *aircraftIdTextField;
Then in my parent class (Entry Detail View Controller) I can't access the property:
//EntryDetailViewController.m (Parent)
#import "PPEntryFlightInfoViewController.h"
- (IBAction)buttonSave:(id)sender {
NSLog(#"save: %#", _aircraftIdTextField); //(!) Error: Use of undeclared identifier '_aircraftIdTextField'
}
How do I access another view controller's IBOutlets when they are in a Container View? Hopefully I'm on the right track. Forgive me as I'm still quite new to Objective-C. :)
View controllers in a container view are children of the controller with the container view. So, you can access the current child view controller with self.childViewControllers[0], and the outlet with [self.childViewControllers[0] aircraftIdTextField]
The short answer is you can't unless you write your own communication layer. You can get at the different views via the childViewControllers (mentioned above) as well as getting your own custom pointers in your prepareForSegue method call as the view is loaded into the container view. (see this link for more info on this) This will work great if you are forcing the user to visit each page. If not then the same defaults you'd load there on the first viewDidLoad can likely be saved without checking the specific view controller.
Apple's answer is to never have a save button. If you edit it, you meant it, and it's saved immediately. =)
That said, were I you, I'd have an object that all of the views access to load/unload their data for storage whenever you show/hide the different views, possibly in viewDidLoad/viewDidDisappear. This way you always have a "known good" object ready for saving, and you won't have to directly access those view controllers.
Hope that helps some.
Clifton, whenever you can, you should avoid having VCs know about each others' controls. You could just have the save button send out a message, and have the three subordinate VCs observe for it. When they get the message, they save their info. That way, the master VC doesn't have to know about controls inside its subordinates.
You need a reference to the current tab view controller, then you ask it for the outlet:
self.entryFlightInfoViewController.aircraftIdTextField
By trying to use _aircraftIdTextField your trying to directly access an instance variable on the container view controller class. Obviously if doesn't have a variable with that name so you get the compile error.