iOS8 - Presenting a modal view removes sub view - ios

I am updating our app to be compiled with xcode6/iOS8.
One issue I am running into is that when a modal view is presented. the underlying subview is removed. It is completely blacked out.. until the modal view is dismissed.. then it re-appears.
Has anyone run into this with iOS8? The same code has worked since iOS4.
Code:
PigDetailViewController *pigDetailViewController = [[PigDetailViewController alloc] initWithNibName:#"PigDetailViewController" bundle:nil];
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
self.navigationController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:pigDetailViewController animated:YES completion:nil];

In iOS 8 they've added a new presentation style that behaves like UIModalPresentationCurrentContext in the circumstance you've described, it's UIModalPresentationOverCurrentContext. The catch here is that unlike with UIModalPresentationCurrentContext, you want to set the view controller to be PRESENTED with this presentation style, like so:
PigDetailViewController *pigDetailViewController = [[PigDetailViewController alloc] initWithNibName:#"PigDetailViewController" bundle:nil];
pigDetailViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
self.navigationController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:pigDetailViewController animated:YES completion:nil];
Note that to support iOS 7 and below you'll likely need to check the OS version and decide how to present the view controller based on that.
edit: I'd like to add one more note to this. In iOS7 with UIModalPresentationCurrentContext, when the presented VC was dismissed, the underlying VC had its viewDidAppear method called. In iOS8 with UIModalPresentationOverCurrentContext, I've found the underlying VC does not have its viewDidAppear method called when the VC presented over top of it is dismissed.

Adding a point to BrennanR's answer.. even viewWillAppear doesn't call when the VC presented over top of it is dismissed.

I think you are misunderstanding how a modal view controller works.
When you present a view controller modally it will control the entire screen. It has an opaque background (normally black) and then draws its view on top of that.
So, if you set the view.backgroundColor to yellow (for example) it will have a yellow background. If you set it to clear then it will show through to the black background.
What I think you want is for the other view to "show through" so it looks like the modal view is sitting on top of it.
The best way I have found of doing this is to use this method...
// in the view controller that is presenting the modal VC
modalVC = // the modal VC that you will be presenting
UIView *snapshotView = [self.view snapshotViewAfterScreenUpdates:NO];
[modalVC.view insertSubView:snapshotView atIndex:0];
// present the modal VC
This will take a "screenshot" of the current view hierarchy and then place that snapshot underneath everything in the modal VC.
That way your black screen will be replaced by a screenshot of the previous view controller.

Related

UIModalPresentationCustom seems to stop modal from auto rotating

So I have a viewcontroller who on a button click presents a modal. So The view controller that is presenting the modal only allows portrait animation. While the modal should allow all the rotation types. So if I present the modal with default animation the rotation works as expected e.g the view controller that is presenting the modal stays in portrait and the modal can rotate freely. So I wanted to use a custom transition to present and dismiss the modal controller. This is snippet which is used to present the modal.
SecondViewcontroller *sec = [[SecondViewcontroller alloc] initWithNibName:nil bundle:nil];
sec.transitioningDelegate = self;
sec.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController:sec animated:YES completion:nil];
So I set up the UIViewControllerTransitioningDelegate methods for presenting and dismissing modals to return my Animator object. So now when I present the modal it now does this custom animation and everything appears to work. Except now the modal can no longer rotate and is stuck in portrait. So I decided to try and see if it was something odd with the animator causing it. So in the UIViewControllerTransitioningDelegate methods that return the custom Animator object I set them to return nil e.g use the default system animation. But no luck, it seems once I set
sec.modalPresentationStyle = UIModalPresentationCustom;
autorotation no longer works.

IOS 7 : Adding modal ViewController with transparency : Custom Size

What I want to do is present a viewController that comes from the bottom and has a custom size. Whatever I seem to do either looks naff (e.g its animated up, flashes then goes transparent), is fullscreen or blacks out the whole screen. I have read a few solutions with custom delegates handing the animation but there must be a simple way. Also a lot of the solutions are for iOS 6 <
HackViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"HackViewController"];
vc.delegate = self;
vc.modalPresentationStyle= UIModalPresentationCustom;
vc.view.frame = CGRectMake(0, 0, 800, 400);
vc.credits = CREDIT_PER_LEVEL * building.buildingLevels;
vc.view.backgroundColor = [UIColor clearColor];
[self presentViewController:vc animated:YES completion:^{
vc.view.backgroundColor = [UIColor clearColor];
}];
If you wanna add viewController (say VC2) as a modal over first viewController(say VC1), then in VC1, when you are presenting VC2,
[self presentViewController:VC2 animated:YES completion:nil];
In VC2 viewDidLoad
[self.view setBackgroundColor:[UIColor colorWithRed:211.0/255.0 green:211.0/255.0 blue:211.0/255.0 alpha:0.8]];
And, in AppDelegate under application didFinishLaunchingWithOptions:
[[self.window rootViewController] setModalPresentationStyle:UIModalPresentationCurrentContext];
You can create other views like imageView or label, etc in VC2
If you only want to support iOS7 and above, you can implement this using a custom modal presentation style (UIModalPresentationCustom) and implement the transitioningDelegate to return a transitioning controller. In the transitioning controller, you will be called when the presentation is to happen, and you can provide the target frame of the presented view controller. This has a big advantage of using the system presentation model, and the system is aware a controller has been presented.
If you need to support iOS6, you need to add the presented view controller's as a subview, the view controller as a child view controller of the presenting view controller, and manager the view hierarchy yourself. This is less than optimal because of manual view hierarchy control and child/parent view controllers.
You don't have to presentViewController:, you can do that with addSubview:
Keep doing what you are doing but add view of vc to view of presented view controller instead of presenting vc with presentViewController:
If you do that within an animation block, it would look nice.

ViewDidAppear not called in main view when modal view is presented over a popover

I'm trying to use a popover as an intermediary menu between my main view and a modal view controller. I can successfully present the Modal view controller from the popover by using the following code:
UIStoryboard *storyboardiPad = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
cbwEditControlPanel *editCP = [storyboardiPad instantiateViewControllerWithIdentifier:#"EditCP"];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:editCP];
[nav setToolbarHidden:NO];
[nav setModalPresentationStyle:UIModalPresentationFullScreen];
[nav setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:nav animated:YES completion:nil];
self.modalInPopover = NO;
The problem I'm running into is that when the EditCP modal view controller is dismissed, the main view controller never updates. I have a pagecontroller on the main view that should be updated to reflect the number of pages as set in the EditCP modal view controller, but for some reason the modal view controller being called from the popover prevents the main view controller from updating the pagecontroller. I've even tried calling the main view's "View Will Appear" method from the popover or modal view when they are dismissed, but even if the 'viewWillAppear' method is called the pageController will not update!
Any ideas what is preventing the pageController from updating? I even passed a reference to the pagecontroller to the modal view and tried to update it there, but it seems that from the time the popover is presented until it is dismissed, I cannot update the number of pages on the PageController.
Thank you!
So this is an old question but I also came across a similar problem recently when using a popover. My solution was to use an unwind segue to trigger my parent view to perform some action. In my case my parent view contains contact information and the popover contains a list of cites. All I wanted to do was to have the parent view update with the new city once the user selected it from the popover. So in my parent view I create my unwind function as follows:
In the .h:
- (IBAction)unwindToContactTVC:(UIStoryboardSegue *)unwindSegue;
In the .m:
- (IBAction)unwindToContactTVC:(UIStoryboardSegue *)unwindSegue
{
[self updateTableForOffice];
}
In the above .m file is where you would have the logic to do whatever it is you want to in the parent view. To connect this unwind segue go to the child view in the storyboard and control drag from the view icon to the exit icon. You should see a pop up with the name of your unwind segue.
Finally, give that unwind segue a name and then in the child controller in the viewWillDisappear() function call the segue as follows:
- (void)viewWillDisappear:(BOOL)animated
{
[self performSegueWithIdentifier:#"unwind-to-contact-tvc" sender:self];
}
I hope that helps. If someone has a better solution let me know.
Well, I half solved the problem. The only way to get an update function when the popover disappeared was to stop using Storyboards and programmatically present the popover, using the main view as the delegate. I then was able to update correctly inside the popoverControllerDidDismissPopover method.
However, I am still interested in finding a way to update the pageControl when the modal is dismissed, before the popover is dismissed.

Present modal ViewController from SubView

I am trying to present a modal view controller C from view controller B. B's view does not cover the full screen, and is a subview of another view controller, A. What I am seeing when I try to present a fullscreen modal is the modal is covering the full screen, but when I tap on certain places in the screen the control will get 'passed through' to A's view.
I can bypass this by presenting the modal from A via some kind of delegation, but I have no idea why this is happening! After all, if you have a tab bar controller managing one of your views, and you try to present a modal view, it covers the full screen just fine. Is there some magic going on behind the scenes?
I don't think there is any official documentation on how the modal is implemented, but any view can get the UIWindow of the UIApplication and call -presentModal... on the rootViewController property. This will have the affect of making your modal full screen. I'm sure there are other ways of achieving the same effect though.
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentModalViewController:myModalVC animated:YES];
In that scenario, you need to implement your own 'modal' methods for all your view controllers, using addSubview: and bringSubviewToFront:. I've done this in one of my larger project where I wanted some different behavior from the modal views.
This worked for me:
UIViewController* vc = [[[UIViewController alloc] init] autorelease];
UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView* topView = [[keyWindow subviews] objectAtIndex:[[keyWindow subviews] count] - 1];
vc.view = topView;
[vc presentModelViewController...
Basically, you create a new UIViewController and attach it to the topmost view on the main window (which is the view the user currently sees).
Simple, but not sure about acceptance and efficiency. This is what I use.
Embed all the view controllers in a mainView below the rootView.
Add any modal views to the rootView while disabling userInteractionEnabled flag for the mainView. The modal view should be added to rootView and not mainView
Once done, re-enable the user interaction for mainView.
Hope this helps...

UIModalPresentationFormSheet, dim is missing

I am trying to display a modal viewController in an iPad app using the UIModalPresentationFormSheet view style. I am looking to produce something similar to the Mail app's new message UI/animation.
There are two things that are not behaving correctly:
The modal viewController that is presented always animates to y=0, i.e. to the very top of the
view and not some pixels below the status bar as it does in the mail app.
The documentation says:
UIModalPresentationFormSheet The width
and height of the presented view are
smaller than those of the screen and
the view is centered on the screen. If
the device is in a landscape
orientation and the keyboard is
visible, the position of the view is
adjusted upward so that the view
remains visible. All uncovered areas
are dimmed to prevent the user from
interacting with them.
However, in my case there is no dimming and I can still interact with the parentView below the modalViewController.
The controller that presents the modalView I do this:
AddNewItemViewController *newItemViewController = [[AddNewItemViewController alloc] initWithNibName:#"AddNewItemViewController" bundle:nil];
[self presentModalViewController:newItemViewController animated:YES];
[newItemViewController release];
In the viewController being presented I do this:
- (void)viewDidLoad {
[nameField becomeFirstResponder];
[self setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self setModalPresentationStyle:UIModalPresentationFormSheet];
[super viewDidLoad];
}
I hope someone can help me out.
Is there some other properties I need to set on the parent and modalViewController?
Is the viewDidLoad not the right place to do this setup?
Thanks in advance:)
You set the transition and presentation styles when you create the modal view, before you call presentModalViewController. Remember, the view that creates the modal view 'owns' that object. You want the owner to set these properties because you might implement this modal view elsewhere in the app and want different transition or presentation styles. This way, you set it each time as appropriate.
AddNewItemViewController *newItemViewController = [[AddNewItemViewController alloc] initWithNibName:#"AddNewItemViewController" bundle:nil];
newItemViewController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:newItemViewController animated:YES];
[newItemViewController release];
You're right in calling becomeFirstResponder in viewDidLoad.

Resources