Must a UICollectionViewController's UICollectionView be its root UIView? - ios

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.

Related

Difference in view hierarchy when adding a child VC in code or IB

Iv'e noticed something quite weird, when I add a child VC to a view hierarchy in IB the hierarchy looks like this
parent vc view
- -container view
- - - -child vc view
when adding it by hand
parent vc view
- - child vc view
Following the instructions from apple, in their guide, they never talk about the container view as part of the hierarchy, however in the code in practice, for example when I am trying to call
- (void) hideContentController: (UIViewController*) content {
[content willMoveToParentViewController:nil];
[content.view removeFromSuperview];
[content removeFromParentViewController];
}
the container view is still "polluting" my view hierarchy. I don't understand the relationship between that container and my child VC.
A practical example in my code, is that I put these viewControllers in a UIStackView and when trying to remove the UIViewController that was inserted with an Embed Segue, I remain with a phantom view. The only way I could find to get access to that view, is an IBOutlet from storyboard.
Anyone have experience in handling, replacing or removing ChildViewControllers added with IB? Or can explain where the difference is coming from and how to get rid of it?
I would say that the "container view" you can use in IB is a bit, well... misleading?
If you select it in the Object Library pane, you get an info popup that lists it as UIContainerView. However, if you search Apple's documentation, that is nowhere to be found.
And, as you have probably noticed, if you connect it with an IBOutlet, it gets set as a UIView.... and if you try to do something like:
UIContainerView *vc;
or
let cv: UIContainerView?
you'll get a "Use of undeclared type" error.
What makes it "different" is only how it behaves in IB, and the automatic "load-and-display" of its embedded Child View Controller. This is much like Segues... you can create and "see" them in IB; you can assign properties to them; at run-time they server a purpose / have actions; but... you cannot create a UISegue in code.
So... if you want to use the visual design-and-embed automation of "container views" in IB, you need to be aware that it is added as a UIView to your view hierarchy, and the .view of its embedded VC is added as a subview to itself... and you'll need to use IBOutlet to have a reference to it at runtime if you want to remove it (or size it or change any other property of it).
When you see "code only" implementations of Child View Controllers, you generally also see code for adding the Child VC's view as a subview of the "main" view (or some other view). It just doesn't seem related to the UIContainerView you can use in IB, because it's never referenced that way.
Does that make sense?

Make UIView subview as default UIView for UIViewController with Storyboard

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.

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.

Floating button over UItableview using storyboards

I have made a table view using prototype cells on tableviewcontroller from storyboards.
I want a floating button over that uitableview. (button won't scroll with the tableview).
While searching for a solution..I found out that it is possible by adding button to the superview (in that case Uiviewcontroller subclasses Uitableview).
Can any one tell me how to do that using storyboards??
I think best thing you have to do is to create a UIViewController and add it a UITableView. Then you can add also the UIButton you want to the view controller's view. Don't forget to set the view controller to be the delegate and data source for your table view, and to add <UITableViewDataSource,UITableViewDelegate> to your view controller interface.
If you must do it using Storyboards and not in code, then you need to use a UIViewController and not a UITableViewController.
Add the UITableView and make it full screen - link up its Delegate and DataSource to the UIViewController and adhere to the two protocols in the .h file of your UIViewController.
When adding the button, drag it into the view hierarchy in the "Document Outline" sidebar, and not by dragging it onto the UITableView. Be careful if you're ever dragging the button around the view because if you drag and drop it on top of the UITableView then it will become a subview of the UITableView. If you want to move it around you'll need to select it and then use the arrow keys.
Anyway, apart from that it should all be very easy - add your constraints to keep it in the right place and you should be able to use the button as normal.

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.

Resources