How to share UIView between transitioning UIViewController's (with addChildUsingController:) - ios

Let's say that on the tap of a UIButton in ViewControllerA the following happens before transitioning to ViewControllerB:
- (IBAction)levelSelectButton:(id)sender {
ViewControllerB* obj = [[ViewControllerB alloc] init];
[self addChildViewController:obj];
CGSize screenSize = [MainScreen screen];
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
obj.view.frame = CGRectMake(0,0,screenWidth,screenHeight);
[obj.view addSubview:_banner];
//[obj didMoveToParentViewController:self];
[self runPushAnimationWithController:obj];
}
When ViewControllerB shows up, I can see my _banner (a GADBannerView object) view in place, but when I return to ViewControllerA it is no longer there.
I have never used addChildViewController:/didMoveToParentViewController: methods before so I don't know if this is expected, but I want to be able to return to ViewControllerA with _banner still visible.
Do I need to retain it?

A view can only belong to a single superview. To quote Apple's docs:
Views can have only one superview. If view already has a superview and
that view is not the receiver, this method removes the previous
superview before making the receiver its new superview.
So when you add your view to a newly created parent view controller, it gets removed from the current view controller's view hierarchy.
I would advise against doing this sort of thing. Just create a copy of the view in both places. If it uses large amounts of data, share the data (model) between view controllers, but not the view objects.
If you are completely set on moving your view around between view controllers, I would add a property to the new view controller and set that property rather than manipulating the other view controller's view hierarchy. You'll also have to pass the view BACK when you return to your current view controller.
You should treat a view controller's view hierarchy as private. Not doing that violates the principle of encapsulation.

Related

Adding a child viewcontroller

I have 2 views, ParentViewController and ChildViewController; I want to nest ChildViewController inside ParentViewController. I have designed ParentViewController and ChildViewController in Storyboard. ParentViewController.m contains the logic for the parent and ChildViewController.m contains the logic for the child. In ParentViewController.m I add the child like so:
ChildViewController *childVC = [self.storyboard instantiateViewControllerWithIdentifier:#"ChildSBI"];
[self addChildViewController:childVC];
My Question: How can I position childVC within ParentViewController (i.e. set it's origin).
It seems like I want to do something like the following:
Alloc init child
Call (void)addSubview:(UIView *)view on the view of the child
How can I position childVC within ParentViewController (i.e. set it's origin).
Remember that a view controller doesn't have an origin -- only its view does. To make a view controller's content appear on screen, you need a view to draw it in. You can have one view controller's view appear in another view controller's view hierarchy, and it's quite easy to do with storyboards.
To set up a parent/child relationship between view controllers in a storyboard, do the following:
Add a container view to the parent view controller's view hierarchy.
Drag an "embed" segue from that container view to the child view controller.
You can use the usual -prepareForSegue:sender: method to let the parent controller pass data to the child.
You can also set things up programmatically, if you prefer, and the code you've got is a good start:
ChildViewController *childVC = [self.storyboard instantiateViewControllerWithIdentifier:#"ChildSBI"];
[self addChildViewController:childVC];
After that, your parent view controller should set the child's view's position and add it to the parent's view, like this:
UIView *childView = childVC.view;
childView.frame = CGRectMake(150, 300, 100, 100); //use whatever coordinates you want
[self.view addSubview:childView];
There's a lot more detail in Creating Custom Container Controllers, but the basic answer to your question is that the container controller should set the size and position of the contained controller's view.

Add view behind tableview in UITableViewController

I'm trying to add this custom control below my tableview in a TableViewController:
https://github.com/zogieosagie/RMEIdeasPullToSortControl
In the example the creator gives, the control is implemented using a ViewController and an added tableview, but I want to use it in a TableViewController. I have created and initialized it as shown in the example but I cannot get it to show up behind the table. Any ideas?
Here is a screenshot of the control above my tableview: https://www.dropbox.com/s/ojfpacxelcy9cqm/Photo%20May%2028%2C%208%2057%2035%20PM.png
Here is my code in the viewDidLoad method:
[self.tableView setBackgroundColor:[UIColor clearColor]];
self.rmeideasPullDownControl = [[RMEIdeasPullDownControl alloc] initWithDataSource:self delegate:self clientScrollView:self.tableView];
self.sortTitlesArray = [[NSArray alloc] initWithObjects:#"Listed from A - Z", #"Listed from Z - A", #"Brand value: HIGHEST - LOWEST", #"Brand value: LOWEST - HIGHEST", #"Founded: OLDEST - NEWEST", #"Founded: NEWEST - OLDEST", nil];
CGRect originalFrame = self.rmeideasPullDownControl.frame;
self.rmeideasPullDownControl.frame = CGRectMake(0.0, 45.0, originalFrame.size.width, originalFrame.size.height);
//It is recommended that the control is placed behind the client scrollView. Remember to make its background transparent.
//[self.view insertSubview:self.rmeideasPullDownControl belowSubview:self.tableView];
[self.tableView addSubview:self.rmeideasPullDownControl];
[self.tableView sendSubviewToBack:self.rmeideasPullDownControl];
Table view controllers do not lend themselves to managing anything other than a table view. In a table view controller the content view of the view controller is the table view.
You should not try to add other views as subviews of a table view.
Those 2 things combined mean that you can't do what you are trying to do.
Instead, you should create a regular UIViewController. In your storyboard, add a container view to the view controller's content view. Create a UITableViewController as a separate scene, and then control-drag from the container view onto the table view controller. That will set up an embed segue, so your table view controller becomes a child view of the regular view controller. Now you can do whatever you want to the main view controller's content view, including adding other views behind the table view.
Do you mean that you are using a Table View Controller on the storyboard? Or do you mean that your backing code is a subclass of UITableViewController?
I haven't used this project before but I'm guessing you are using a Table View Controller on the storyboard, in which case there is no backing view for the RMEIdeasPulldownControl to attach to (the top-level view is a UITableViewController). If you look in the example it needs to be attached to a scrollview (like a table view) but it needs to be inserted into a view (like a UIView)
If you meant the second one then I'm not sure, UITableViewControllers are subclassed from UIViewControllers and are really very similar, so I can't imagine any trouble arising from that.
It isn't possible directly, but you can create UIViewControllerClass with relevant storyboard UIViewController
add a MyUIView in hierarchy then UITableView next to MyUIView
attach datasource and delegates for UITableView and use MyUIView as per your requirement.

Manage uiview and uiviewcontroller

I created an uiview , that contained , many textfields , and I have an uiviewcontroller with xib file responsible for making signature .Is it possible to add this viewcontroller to my uiview in order to have this componant of drawing signature in the footer of my uiview ??
- (void)init { //parent view
...
FooterViewController *fvc = [[FooterViewController alloc] initWithNibName:#"myNibName" bundle:nil];
[self addSubview: fvc.view];
fvc.view.origin = CGPointMake(0, self.frame.size.height - fvc.view.frame.size.height);
}
this is how you can create your viewController from xib file and add its view to the main view. assuming this is what you are trying to do.
If you are using storyboards, the easiest way to go is to drag a Container View object from the Object library (where buttons, labels, etc. are) to your view controller's view. This will create a child view controller that you can handle separately and that will be already resized to mirror the size of the container view controller.

popover content view doesn't display while viewcontroller has a child VC present

I have a container view controller that consists of a navigation view at top, and a content view for the remainder of the screen. The navigation menu consists of several buttons, some of which present a popover with UITableView for secondary navigation. This all worked until I assigned a child view controller and set it's view as subview of the content view. Now, the popover appears, but has nothing inside it (no tableview, just black).
Why is this?
Here's the code I added for the child vc in container view:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
ContentWebViewController *initialVC = [[ContentWebViewController alloc] init];
[self addChildViewController:initialVC];
initialVC.view.frame = self.view.bounds;
[self.containerView addSubview:initialVC.view];
self.currentController = initial;
}
See the screenshot below. I added a vc with a simple webview showing google (just as a placeholder for now). The popover was working fine before I assigned the child VC.
Maybe it will help other in other cases -
If you are using size classes (probably you are since you are developing this to iPad) -
Design your popover view controller in Any-Any size and it should be OK - after that you can return to your wanted size.
(You can also uninstall the size classes of any object in that view controller instead of redesign the VC)
I somehow (don't ask me how) changed the class that my table view controller was inheriting from. It should have been (obviously) UITableViewController, but was UITableViewController, so initWithStyle was not being called....

Do I have to use PresentModalViewController?

I'm doing some "interesting" view transitions, and I'm finding myself working around the functionality of "presentModalViewController" in a way that doesn't feel right.
I'd prefer to take total control over the presentation of the modal view controller's view and skip "presentModalViewController" altogether.
However, I'm not sure about the ramifications of doing this.
Currently, I've got code that looks works something like like this (this is just a pseudo-code example, and I can't use the built in transitions, they won't do what I need):
// Create the child view controller:
ModalViewController * child = [[ModalViewController alloc] init];
// Present it:
[parentViewController presentModalViewController:child animated:NO];
// This rect is what the child view's ultimate "destination" should be,
// and, what the parent view's old frame was:
CGRect frame = child.view.frame;
// Put the parent view controller's view back in the window:
[child.view.window insertSubview:parentViewController.view belowSubview:child.view];
// Show it if it's hidden:
[parentViewController.view setHidden:NO];
// Put the parent back where it was:
[parentViewController.view setFrame:frame];
// Put the child at the "top" of the screen (the bottom edge
// of the child's view is at the top of the screen):
[child.view setFrame:CGRectMake(frame.origin.x,
frame.origin.y - frame.size.height,
frame.size.width,
frame.size.height)];
// Animate a transition which slide the parent and child views
// down together:
[UIView animateWithDuration:0.7 animations:^(void) {
child.view.frame = frame;
parentViewController.view.frame = CGRectMake(frame.origin.x,
frame.origin.y + frame.size.height,
frame.size.width,
frame.size.height);
} completion:^(BOOL finished) {
// We're done, remove the parent view from the window
// like it's supposed to be:
[parentViewController.view removeFromSuperview];
}];
[child release];
If you don't want to have UIKit set modalViewController and control the presentation and dismissal of the child view controller, then don't. You can skip the presentModalViewController:animated: call and manually add or remove subviews, or if you want to switch to an entirely new view controller then disconnect the old one's view from the heirarchy and connect the new one, etc. Other ways of presenting include UINavigationController or a UITabBarController, and they don't use the modalViewController methods.
To be more specific, you should set the rootViewController property of your application's UIWindow to the new view controller.
Docs say:
The root view controller provides the content view of the window. Assigning a view controller to this property (either programmatically or using Interface Builder) installs the view controller’s view as the content view of the window. If the window has an existing view hierarchy, the old views are removed before the new ones are installed.
Note that the docs mention an automatic process of installing the view as the content view of the heirarchy. What I'm saying is you can use the provided automatic methods - UIWindow for root views, modalViewController and other systems for non-root views - or you can do it manually, but it's accomplishing the same thing. Particularly since the rootViewController property has only existed since iOS 4, and applications prior to this used auto-generated default code of [window addSubview:rootView] at launch.
If UIKit has some extra magic occurring in [UIWindow setRootViewController:] I'm totally prepared to be corrected on this though.

Resources