Page view controller inside Container presents View controller overtop UI - ios

In my app, I have a nav bar and two toolbars visible in the main View Controller. I then have a container view in that main VC that fills the screen, behind the UI elements. I embedded a UIPageViewController in the container. I then set up a UICollectionViewController scene that is reused when swiping between the pages. This is done in code - see below. Basically, it presents the UICollectionViewController on screen.
It's working well, except when it appears on screen it covers up the UI of the main VC. I could change the height to reveal the UI, but I do want it to take up the entire screen. I just want it to lie behind the toolbars. That way when the user scrolls the Collection VC the content will be rendered underneath those translucent toolbars.
I understand why it's behaving the way it is, but I don't know how to fix it. I originally figured since it's all embedded in a Container it would respect the z-order of that container which appears fine in the storyboard, but I suppose if I'm just throwing the VC on screen in code I should expect such behavior. I'm just not sure how to get the desired behavior. Thanks for the assistance!
//the following code is in the main view controller
//set first page view controller
ContentCollectionViewController *startingViewController = [self viewControllerAtIndex:0]; //calls method below
[self.pageViewController setViewControllers:#[startingViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
//move page view controller down to reveal the underlying UI and show my issue
self.pageViewController.view.frame = CGRectMake(0, 80, self.view.frame.size.width, self.view.frame.size.height);
//display created page VC
[self addChildViewController:self.pageViewController];
[self.pageViewController didMoveToParentViewController:self];
[self.view addSubview:self.pageViewController.view];
//in the viewControllerAtIndex method:
ContentCollectionViewController *contentCollectionViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ContentCollectionViewController"];
//set properties here...
return contentCollectionViewController;

I was finally able to solve it by changing
[self.view addSubview:self.pageViewController.view];
to
[self.view insertSubview:self.pageViewController.view atIndex:1];

Related

Present child view controller

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.

View Shifts on UIPageViewController

I have a UIPageViewController with a first view that is inside a navigation controller. When the view is first displayed the nav bar covers the top part of the view. As soon as I start to swipe the page, the view drops below the nav bar. From then on the view will layout correctly. How can I fix this? What is causing this?
I was having the same problem. To fix it, set automaticallyAdjustsScrollViewInsets to NO before calling -setViewControllers:direction:animated:completion:.
self.automaticallyAdjustsScrollViewInsets = NO;
[self setViewControllers:#[firstPageViewController]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];

Prevent clicks on view that presented another view via UIModalPresentationFormSheet

I have a view that is presenting another view via
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
[weakSelf presentViewController:navigationController animated:YES completion:^{}];
The only problem is that the "main" view that presented that new view, has buttons that can be touched because the ModalPresentationFormSheet doesn't take the full screen. I would like to keep that format, but prevent clicks while the Modal is being presented. I know I could do this this check on every possible buttons, but I am sure there is another way!
if (![weakSelf presentedViewController])
Thanks!
You can put the "new view" as a child view of another view that has full screen and make that "parent view" background color to clear color so you can see the "main view" also. Now you can't click the button cause you are actually clicking the view that is the parent on "new view"
One approach could be to place an invisible 'shield' above the hosting view controller, but below the form sheet.
Basically, create an empty UIView whose background color is clear. Add that as a subview to your presenting view controller just before you make your call:
[weakSelf presentViewController:navigationController animated:YES completion:^{}];
Now, this doesn't necessarily mean such a solution is in good taste. That is, the form sheet style isn't meant to be exclusive in that way, and it can be confusing if the UIView installed above is clear. So, you could reduce the alpha value on that view to turn it into a dimming screen, to help the user understand that the form sheet is the only thing they can interact with at that time:
UIView *dimmingScreen = [[UIView alloc] initWithFrame:self.view.bounds];
dimmingScreen.alpha = 0.5; // play with this value to get different degrees of dimming
dimmingScreen.backgroundColor = [UIColor blackColor]; // play with different colors
[self.view addSubview:dimmingScreen];
// Now present your form sheet, as you were:
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
[weakSelf presentViewController:navigationController animated:YES completion:^{}];
You'll want to be able to remove the dimming screen too, so best make it a view controller property you can access so as to remove when needed.

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....

Display Modal View Controller over detail view in UISplitViewController

I have a UISplitViewController in an iPad app. When something is selected from the table I want to fade in a modal view controller over the detail view. I can present it without a problem, but for some reason I can't get it to match the frame of the detail view. I would like it to stick to the detail view controller frame on rotation as well. Does anyone have any experience with this? This is my code to display. The detail view controller reference is set in the app delegate and passed down the table controllers.
QuestionViewController_iPad *questionView = [[[QuestionViewController_iPad alloc] initWithNibName:#"QuestionViewController_iPad" bundle:nil] autorelease];
questionView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
// Not quite
questionView.modalPresentationStyle = UIModalPresentationCurrentContext;
questionView.questionQuizCon = [QuestionQuizConnection firstQuestionForQuiz:quizCatCon.quiz];
// Maybe something like this?
[self.detailViewController presentModalViewController:questionView animated:YES];
When the modal view presents, it matches the size of the detail view controller, but it doesn't but it sits on the top left of the screen behind the master view controller. It also doesn't resize on rotation. I have the springs and struts set to auto size and fill. The height changes on rotation but it won't fill the width.
I couldn't get this to look right any way I tried it so I ended up just using view transitions to make it look like pages being torn off a notebook. That looks better anyway.
// Transition the view on as a subview.
[UIView transitionWithView:self.detailViewController.pageView duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:^ {
questionView.view.frame = CGRectMake(0, 0, self.detailViewController.pageView.frame.size.width, self.detailViewController.pageView.frame.size.height);
[self.detailViewController.pageView addSubview:questionView.view];
// Watch this one
self.detailViewController.currentQuestionViewController = questionView;
}
completion:nil];
After [self.detailViewController presentModalViewController:questionView animated:YES]; you should set center property and/or frame of questionView. Be sure that you set it after presenting modal view.

Resources