Make UIView subview as default UIView for UIViewController with Storyboard - ios

I have a multi-viewcontroller app.
The main view of the main VC is subclassed so I can use Core Graphics animations. It's called "animations" class.
On the storyboard, I add a UIView called "MainArea" as a subview of the "animations". I have a VC called "MainAreaVC". As you know it has a property of "view". How can I make the "MainArea" subview the default UIView of my "MainAreaVC"?
The other option is to just make the "MainArea" view a property of my "MainAreaVC" and use this. I just don't want the "MainAreaVC"'s default "view" property just hanging out doing nothing.

The view in a UIViewController is the bottom view: it is always the one at the root of the tree hierarchy, and appears behind everything else, possibly clipping subviews.
You can change the view Class, but no matter what you do, by design it must be at the root. If, somehow, you managed to point to one of your subviews, that subview would in essence become the root.
Comment:
You do not have to add a view of type animations containing another view of type mainArea. You can have 'MainAreainherit fromanimations, and drag suchMainArea` in the storyboard.

Related

Is it bad practice to put UIViewControllers in other UIViewControllers?

I know there is the common practice in iOS development of having one UIViewController presented on the screen whose view is loaded from a XIB which will contain all the UIView subclasses in it.
While I was working on a pretty complex widget for an app, I decided to make the widget subclass a UIViewController instead of a UIView. This was because I thought a UIViewController was essentially a UIView with some helper methods around it. Then I could create a XIB for it (I know UIViews can have their own XIBs too), load the views it contains, place ITS view in the presented parent VC's view, and lay it out.
This works fine so far, but I'm wondering if this is bad practice and if I should just subclass a UIView instead and give it a normal NSObject controller. I am seeing some problems with this and I was wondering if anybody could address concerns I have with this approach?
EDIT NOTE: The widget VC does NOT relate to the VC view it is in and is reusable on ANY screen. So the answer is not subclassing the widget VC with the parent VC. The widget is INSIDE the parent VC, but it is NOT a parent VC.
EDIT NOTE 2: I am NOT using Storyboard. Only Autolayout, XIBs, and ARC.
Why can't we have VC's in VC's?
1) Can VC's be simply dropped into ANOTHER VC's XIB and be loaded easily as a subview?
2) I read here: When to use a UIView vs. a UIViewController on the iPhone?
The top answer explains how the VC controls rotation of the screen and laying out the subviews again, so if you add another VC, then the system will automatically think that THAT is the main VC and will attempt to rotate it instead, causing problems. Is this true? Or is he just talking about if you somehow got into a state where 2 VC's were "presented"? I wasn't sure if his answer applied to VC views that were SUBVIEWS of other VC views.
3) In general is this good practice? It certainly seemed more reasonable as it made loading the subview VC's view much easier.
Thanks!
It's absolutely fine. The answer to your problem is ContainerView.
Container View defines a region within a view controller's view subgraph that can include a child view controller. Create an embed segue from the container view to the child view controller in the storyboard.
You almost got it right. Yes, it's good to make a view controller for what you needed. But you shouldn't just add it's view to the parent view, you should also add the view controller as a child view controller of the first view.
You can add many views controllers as child view controllers of a view controller.
You can learn more about this here.

MVC with view built in code

I've been trying to interpret the lessons from CS193P, and have a few questions.
I'm building views in code, the way I do it is I have a UIView subclass where I put all the views in place in the init method. This class is initialized by the ViewController.
The question is then, what is the right approach from here - say i want to animate a button I placed at 0,0 to 100,100. I'd like to animate it from the ViewController, but i don't like the fact that i set the 0,0 position in the UIView class (in the initializer) and now i am setting a new position in the ViewController. I'd prefer there would be just one place knowing about the actual (x,y) positions of my views.
How am i supposed to go about this?
Move the positions in the initializer to the ViewController
Put a method in my UIView "-(void)AnimateToSecondPosition" where the actual "second position" is then up to the view?
Just let it go. It seems like this would be the right approach if i had placed the button in interface builder - i consider interface builder to be the view then...
Or maybe even a fourth option?
Please help me understand it better and not just give me the right answer ;)
I'd like to be able to compare my approach in some way to how you would do it using interface builder, so each of my views are public and accessable from the controller - this way i believe i could easily start using interface builder instead if i wanted, without changing the controller code, just hooking up the outlets.
I'm guessing the case would be the same for disabling, hiding and doing other things with the views.
Thanks in advance.
If you want to create a new View programmatically you should generally instantiate it in your View Controller using its designated initialiser:
UIView *testView = [[UIView alloc]initWithFrame:myFrame];
If you create a custom view it's totally fine and correct to put some configuration code in the init method, but it's your ViewController that should be in charge of deciding what to do with this view - it is his job! Using the MVC the View and the Model should never communicate directly (as you definitely learned in the first lesson of CS193P).
Therefore the same apply to the animations. You should animate the Views within your ViewController and not implement the animation in the View itself.
Therefore in my opinion you "second position" should be setup by the VC - if this has to be done when something happens to the view (e.g. someone pressing a UIButton) you should set a target/action to your VC and handle this within your VC.
ADDED:
Regarding building UIViews in the Interface Builder I don't know what you mean by "and let them go". Interface builder will create the views and add them to the specific superviews at runtime - as you can see in the example below you control the view hierarchy graphically on the left. For instance in this case there is a UIView (which I coloured green for clarity) and two buttons. One is a subview of the main view while the other is a subview of the green UIView.
Once your ViewController is loaded the view hierarchy is automatically loaded to self.view - in fact if you run the following code in your VC when it is loaded you will see the list of self.views subviews in your console.
for (UIView *view in self.view.subviews){
NSLog("%#", [view description]);
}
If you know already that you need to change some attributes of a specific UIView you setup via Interface Builder (e.g. we know we want to change programmatically the color of the green UIView in the example above) you should create an outlet which allows you to have a reference to that view in your code. You do it by crtl-drag from the storyboard to your ViewController code - see the example below.
When you have done that you can refer in code to this as any other property, with the difference that it has been created by Interface Builder.
Hope this helps.
You can add an -setButtonFrameToSecondPosition to the view subclass, which simply updates the frame of the button, and then call that from the view controller via one of the +[UIView animate:...] methods.

Must a UICollectionViewController's UICollectionView be its root UIView?

In a storyboard, I'd like to describe a UICollectionViewController that has a plain UIView as its root view (the view parameter). The root view will be a container holding the UICollectionView as a child, with another UIView in front of it.
(I want to place my own UIGestureRecognisers in front of the UIColellectionView's to pick up pans and pinches. I'll disable the UIColellectionView's "User Interaction").
The storyboard editor doesn't seem to want me to do this if I drag a UICollectionViewController from the "Object Library". Can it be done? Would I be better off subclassing from UIViewController instead of UICollectionViewController?
The very short answer to the questions: Yes, it must. UICollectionViewController requires it's [self view] to be the UICollectionView instance.
Instead of doing this, have a top level UIViewController owning the UICollectionViewController as a child. This suitably separates the code / logic / ownership of each of the views and correctly allocates controllers for each section of your 'view'.
If you are setting up from code, use UIViewController as the owner of the top level view and use addChildViewController: to handle the nested collection view controller.
If you are setting up from a storyboard, have a UIViewController scene that has a view hierarchy of your choosing but includes a "Container View" object from the storyboard editor's "Object Library" somewhere in it. Have the UICollectionViewController in a separate scene. Point the "Container View" you added at the UICollectionViewController's scene in the storyboard.
UICollectionViewController Is a lot more restrictive than UICollectionView. Same goes for UITableViewController. UITableViewController for example won't let you add another UIView to it without effecting to the UITableView hierarchy table view.
As a matter effect, I hardly use those ViewControllers and always prefer to use the original UICollectionView.
Just drag a UIViewController to your story board and drag a UICollectionView on top of it.

How the view and viewcontroller hooked?

I cannot find where the view and viewcontroller get hooked? Is it in the xib file?
I learned that each viewcontroller can control several views, but where are those two get hooked?
I recommend you to read the whole ViewController Programming Guide if you have doubts like that:
ViewController Programming Guide
In case you want to jump right to your issue, check this section:
Resource Managment in ViewControllers
You can find a nice graph explaining where the views are created and linked in the ViewController:
A ViewController is just that, a class to manage the UIViews (there will be many) that it contains. The main view is automatically wired up for you and you are responsible for wiring up all the other views you add. Keep in mind that UIButtons, UILabels, UIViews, etc are all objects that inherit from UIView.
Like Antonio indicated, start with the Apple docs:
The view controller has its own view. Each child view (subview) view has a parent view (superview). You can nest views inside of views. In your case, the top view in the hierarchy is the view controller's view.
At design time, you can add a child view to any view in Interface Builder by simply dragging a new view onto the parent view. You can also adjust the view hierarchy from the Document Outline in Interface Builder.
When creating a view hierarchy in Interface Builder, the view hierarchy is stored in the .xib file.
At run time, your views are instantiated from the information in the .xib file, and each child view's superview property points to its parent view. Each view also has a subviews property that lists each of its child views.
You can add a view to any other view at run time by instantiating a new view and passing it to the parent view's addSubview method. Obviously, once instantiated, you can alter the view hierarchy by setting the superview and subviews properties and calling related methods.

Top level view in a UIView hierarchy

I have a singleton instance of a custom UIView with a method -(void)display whose job is to animate the custom view in and out on whatever screen is currently being displayed. (kind of like the -show method in UIAlertView).
My question is how do I determine which view is at the top of the UIView hierarchy and currently displayed?
The "top" of the view hierarchy is a UIWindow. And there can be (and usually is) more than one UIWindow in the application. If you want to have something shown over everything else on the screen, I suggest you implement a custom UIWindow. E.g. UIAlertView is also implemented this way.

Resources