I'm adding 5 viewcontrollers to a scrollview with a page control so I can swipe from one viewcontroller to another.
At initialization I'm loading 3 viewcontrollers (left, middle, right)
My problem is that my three viewcontrollers are firing a viewDidAppear but only the center viewController is visible...
Is there a way to avoid the view controllers that aren't visible to call viewdidappear?
I'm adding my viewcontrollers to my scrollview like so :
if (controller != nil){
[self addChildViewController:controller];
[controller didMoveToParentViewController:self];
}
[scrollView addSubview:controller.view];
No, the viewDidAppear method is not related to the visibility of the view, if you get the documentation you will see
Notifies the view controller that its view was added to a view hierarchy.
So this method will be called when the view is added to the hierarchy. So the view was loaded, and added to the hierarchy, even in a non visible space of your mainView, it will call viewDidAppear.
To achieve what you want, you should implement the delegate of the scrollView, check the offset, and see in which page you are, then you can call a method on your viewController to do the job you want.
Related
I have a UIPageViewController subclass that shows images. This view controller is inside a larger view controller that has other content. I want to be able to tap on an image in the page view controller and have that page view controller removed from where it is and presented full screen, where additional controls such as zooming and panning around the image would be available. Then, I also need a way to be able to dismiss it from being presented full screen and to re-insert it in the original parent view controller.
- (void)handleTapGesture {
UIViewController *parentViewController = self.parentViewController;
[self didMoveToParentViewController:nil];
[self.view removeFromSuperview];
[self removeFromParentViewController];
self.modalPresentationStyle = UIModalPresentationFullScreen;
[parentViewController presentViewController:self animated:YES completion:nil];
}
But when I do this, I can see the dimming view and everything that is set up automatically when presenting the view controller, but the view controller itself is not visible.
I viewed it in the view debugger, but it looks like the frame of the page view controller is zero sized. Here is some output from the debugger:
Unbalanced calls to begin/end appearance transitions for <MyPageViewController: 0x10ca8f000>.
Printing description of $21:
<_UIPageViewControllerContentView: 0x117b04c40; frame = (0 0; 0 0); clipsToBounds = YES; opaque = NO; autoresize = W+H; layer = <CALayer: 0x283491be0>>
I am not sure why that is though and I do not know how to debug this since I am not specifying any layout explicitly. From what I understand, when I present this view controller, I should not have to specify any constraints or sizes as that is to be handled by the view controller transition. All I am doing is trying to make a view controller, that was a child view controller, be presented modally full screen.
The view containment calls are incorrect. (See below.)
But the “Unbalanced calls” error message suggests that there might be some other, deeper problem elsewhere in your code base. The incorrect view controller containment calls are insufficient to manifest this error.
One generally gets this error when attempting to initiate a transition while another is underway (e.g., trying to present/dismiss view controllers inside the viewDidLoad, viewWillAppear or viewWillDisappear methods).
But the supplied code snippet is insufficient to manifest the problem you describe. We need MCVE. I would suggest you create a blank project and figure out what you need to add to it in order to manifest your error.
That having been said, the correct view controller containment calls to remove a child are willMoveToParentViewController, followed by removeFromSuperview, followed by removeFromParentViewController, e.g.:
[self willMoveToParentViewController:nil];
[self.view removeFromSuperview];
[self removeFromParentViewController];
Note, I did not call didMoveToParentViewController, because, as the documentation says:
The removeFromParentViewController method automatically calls the didMoveToParentViewController: method of the child view controller after it removes the child.
Obviously, when adding a child, the converse is true, that you do not call willMoveToParentViewController, but you do call didMoveToParentViewController:
[self addChildViewController:child];
[self.view addSubview:child.view];
child.view.frame = ...;
[self didMoveToParentViewController:self];
Again, the documentation advises us:
When your custom container calls the addChildViewController: method, it automatically calls the willMoveToParentViewController: method of the view controller to be added as a child before adding it.
I have a UINavigationController, containing a UIViewController that is parent to two UITableViewController controllers.
When the user taps on a segmented control in the UIToolbar of the navigation controller, the current child table controller is swapped out with the new one. This includes removing the old controller from the parent hierarchy and removing its view as a subview of the parent view controller.
The first view controller that is displayed when the navigation view controller first presents it has its contentInset correctly configured by automaticallyAdjustsScrollViewInsets, however, when I pull that one out and insert the view from the second table view controller, that does not.
Furthermore, if I rotate the device (Which shrinks the UINavigationBar) and then swap back to the first view controller, its contentInset is now incorrect and it doesn't scroll properly. The second controller, however, does have its contentInset property properly set as a result of the device rotation.
Is there a way to manually force a UIViewController to redo its automaticallyAdjustsScrollViewInsets operation when I need it?
It's not an absolutely amazing one, but I found a solution that works.
Inserting a new child view controller isn't enough to trigger UINavigationController to automatically work out the appropriate contentInset values for any scroll views in the new child. BUT! You can force it to perform that calculation by doing something that would have required it anyway. For example, hiding and showing the navigation bar or toolbar.
- (void)insertViewController:(UIViewController *)viewController
{
// Add the view to our view
viewController.view.frame = self.view.bounds;
[self.view addSubview:viewController.view];
// Add the new controller as a child
[self addChildViewController:viewController];
[viewController didMoveToParentViewController:self];
// Show and hide the toolbar to force the content inset calculation
self.navigationController.toolbarHidden = YES;
self.navigationController.toolbarHidden = NO;
}
I've tested it, and there appear to be no visual glitches by rapidly hiding either the navigation bar or toolbar, so this solution seems to be acceptable.
I have a case where all my subviews of a viewcontroller (say A) are declared in the loadView method. When I remove the viewcontroller's view (say B) from the superview and add back viewcontroller A's view to the superview, how can I reload the view? Subview B is on top of subview A and when I remove B I should be looking at an Update subview A.
Simply removing the view doesn't destroy it. But if you have destroyed the view (by calling [viewcontroller setView:nil]), then simply calling [viewcontroller view] will reload the view. You should never call loadView - the system will do it for you.
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....
I am trying out an application using a child ViewController inside another viewController.
I have a VC and I am instantiating another VC with its own xib inside the outer VC.
I am adding it as a child using the new iOS 5 method addChildViewController and also I have added its view as a subView.
But how do I control its position and size inside the parent view controller ?
should I modify the frame of the child controller's view ?
or I have to adjust the freeform view in the xib itself ?
Also in my current implementation, the child view starts behind the status bar of the parent viewcontroller's view.
Any idea on how to systematically implemement something like this ?
#define SUBVIEWS_FRAME CGRectMake(0,20,100,100) // whatever frame you need
- (void)addChildViewController:(UIViewController *)childController{
[childController.view setFrame:SUBVIEWS_FRAME];
[super addChildViewController:childController];
}
Simply just add a view in parentViewController #synthesize that view like childView. now add your childViewController as a subView in childView of parentViewController. it will simple to adjust using parentViewController View on nib file. If you have a large childViewController then please use UIScrollView instad of UIView