iOS: Apply view rotation to view controller under modal view - ios

I have been following a solution on this question in order to display a view with a transparent background. The issue that I'm having is once the modal view controller has been displayed, the underlying view doesn't get rotated anymore.
For example if A is my view controller, then B is my modal view. The issue is as follows. I currently have my device in portrait and have A displayed. I then present B modally. I then rotate my device and B rotates with it, however A stays as it was.
Please could someone advise on how to handle this rotation so that the underlying view (A) gets rotated too?

ModalViewController is used to interrupt the current workflow and displaying a new set of views. So when you present modally, here in this case you are presenting B, the current active Viewcontroller is B and not A.
A ViewController is traditional controller objects in the Model-View-Controller (MVC) design pattern. They also take care of user interface, gesture recognitions,event management(of buttons for example) and the alignment of views in present in them.
When you presented B, the current viewcontroller changed from A to B and hence when you try to rotate(if the orientation support is provided) the view of B is effected as its the viewcontroller active and it responds to the rotation. Normally we go unnoticed these because the view is opaque. Here in your case the view is transparent and we notice that A has not responded to rotation.
I tried the above example in iOS6 (from the one you mentioned)
ViewController2 *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"VC2"];
vc.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:vc animated:YES completion:nil];
here A remained in portrait mode
When i did this adding the second viewcontroller's view as a subview, A changed to landscape
ViewController2 *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"VC2"];
vc.view.backgroundColor = [UIColor clearColor];
self.view addSubview:vc.view];
this happend because in the second trial the active viewcontroller was A and not B as B's view was a subview added to A. Go through Apples's Document on
About ViewController
About windows and views
Presenting ViewControllers

Related

iOS 8 bug with dismissViewControllerAnimated: completion: animation?

iOS documentation for dismissViewControllerAnimated:completion: states:
If you present several view controllers in succession, thus building a
stack of presented view controllers, calling this method on a view
controller lower in the stack dismisses its immediate child view
controller and all view controllers above that child on the stack.
When this happens, only the top-most view is dismissed in an animated
fashion; any intermediate view controllers are simply removed from the
stack. The top-most view is dismissed using its modal transition
style, which may differ from the styles used by other view controllers
lower in the stack.
This means when dismissing two modal view controllers at once using
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
the animation shown should be the top modal view being dismissed.
This is indeed the case in iOS 7 and prior, but in iOS 8 the animation shown is not the top-most view (in my experience, it's the second top-most view). Is this behavior a bug in iOS 8 or am I doing something wrong?
As commented above: I see the exact same issue in an unwind segue context. I just toke the workaround as described here using a screenshot and add it as a subview to all intermediate viewControllers: How to dismiss a stack of modal view controllers with animation without flashing on screen any of the presented VCs between the top and bottom?
// this in during unwind in a custom UIStoryboardSegue (that is the reason why it might look wrong with what is what: srcViewController and destViewController
UIViewController* aPresentedViewController = destViewController.presentedViewController;
while (aPresentedViewController != nil) {
if (aPresentedViewController == srcViewController) {
break;
}
UIView *anotherSrcViewCopy = [srcViewController.view snapshotViewAfterScreenUpdates: NO];
anotherSrcViewCopy.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[aPresentedViewController.view addSubview:anotherSrcViewCopy];
// recurse through the presentedViewController hierarchy
aPresentedViewController = aPresentedViewController.presentedViewController;
}
Same problem and same solution here than #theguy.
Here's my version in Swift without iterating on all the view controllers :
guard
let presentedViewController = segue.destination.presentedViewController,
let viewToCopy = segue.source.view.snapshotView(afterScreenUpdates: false)
else { return }
viewToCopy.autoresizingMask = [.flexibleWidth, .flexibleHeight]
presentedViewController.view.addSubview(viewToCopy)

UIViewController Present

I am trying to present a UIViewController with a UIView on it.
The following is the code I am trying in my viewDidLoad method.
//create the view controller
UIViewController *controller = [[UIViewController alloc] init];
UIView *view = [[UIView alloc] init];
view.backgroundColor = [UIColor whiteColor];
controller.view = view;
//show the view
[self presentViewController:controller animated:YES completion:nil];
When I run the app, it is giving me the following error.
Warning: Attempt to present <UIViewController: 0x751fcd0> on <ViewController: 0x751d7a0> whose view is not in the window hierarchy!
What does this mean and where am I going wrong? Shouldn't it display a white view or am I understanding wrong?
Thanks.
The solution is to move my code to the viewDidAppear method.
I'm assuming that the view controller's view is not in the window hierarchy at the point that it has been loaded (when the viewDidLoad message is sent), but it is in the window hierarchy after it has been presented (when the viewDidAppear: message is sent).
If you call presentViewController:animated:completion from 'viewDidLoad:' it won't work. And that is why:
The area of the screen used to define the presentation area is determined by the presentation context. By default, the presentation context is provided by the root view controller, whose frame is used to define the frame of the presentation context. However, the presenting view controller, or any other ancestor in the view controller hierarchy, can choose to provide the presentation context instead. In that case, when another view controller provides the presentation context, its frame is used instead to determine the frame of the presented view. This flexibility allows you to limit the modal presentation to a smaller portion of the screen, leaving other content visible.
View Controller Programming Guide for iOS: Presenting View Controllers from Other View Controllers
In viewDidLoad frame of presenting view controller simply not set yet. That is why you should present next controller only when presenting controller is on screen.

Presenting a view controller of custom size with navigation

I want to present a view controller of custom size say (500,500). I try to do that with the below code, it works fine with a semi transparent light gray background if I present the view controller alone but when i put the view controller in a navigation controller (which I want to do) there is a black background that comes up, I dont want this and I want the gray one.
I did the following code with the help of this question:
iOS -- how do you control the size of a modal view controller?
MyViewController *vc=[[MyViewController alloc]initWithNibName:#"MyViewController" bundle:nil];
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:vc];
nav.modalPresentationStyle=UIModalPresentationPageSheet;
[self.window.rootViewController presentModalViewController:nav animated:YES];
CGRect r = CGRectMake(self.window.rootViewController.view.bounds.size.width/2 - 250,
self.window.rootViewController.view.bounds.size.height/2 - 250,
500, 500);
r = [self.window.rootViewController.view convertRect:r toView:vc.view.superview.superview];
vc.view.superview.superview.frame = r;
Any guess, what I am missing here?? Or is there a easy way to present a custom size VC with navigation??
With navigation:
Without navigation: (i am using a dark background, so it may appear like it is black but it is not)
Just putting transparent overlay on the view controller and present it, sothat it looks like as what you actually want...
Also refer the following link,
Show modal view controller with custom frame in iPad
How to present a modal view controller with custom size in center?
iPad custom size of modal view controller
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html

Rotate view below modal view

I have an UIViewController(called MainViewController) which presents modally a semi-transparent view (HelpOverlayViewController):
HelpOverlayViewController *helpOverlayViewController = [[HelpOverlayViewController alloc] init];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
helpOverlayViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:helpOverlayViewController animated:YES completion:nil];
If the user rotates the device while the HelpOverlayViewController is shown it only rotates HelpOverlayViewController and not the MainViewController i.e. the parent controller. This is a problem since HelpOverlayViewController is semi-transparent and MainViewController is visible below it.
Both controllers have the method
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
They both rotate fine independently.
Is there some way I can force the underlaying view controller to rotate when the modal view does?
I do know that issues like this will likely be largely resolved with iOS 6 as it has a different model for handling rotations.
However, that doesn't help you now. You might be best off just making your HelpOverlay a UIView and not a UIViewController. You can add this semi-transparent view onto the top of your MainViewController (or any other). You can still create an animation (like a fade-in) when adding this subview to your view hierarchy. With this model, you'll no longer have any issues with rotations.

With UIPresentationFormSheet, why doesn't my view move above the keyboard when it is up?

Apple 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.
But my view doesn't move up when the keyboard is visible. I basically want to present a textview modally above the keyboard so the user can enter text and then hit send (in a nav bar button on the presented view.)
My presenting view is a UISplitViewController (not one of its children) and I'm presenting UINavigationController who's top view controller is basically a UITextView. Rotation works, but the presented view is overlapped by the keyboard in both orientations.
I found some questions asking how to resize the presented view in this case, which is nice, but I don't want to have to make assumptions by resizing manually in the presenter or in the presented view. It seems like it should just pick a decent (undocumented) size just move it up automatically when the keyboard shows.
My presenting code looks like this:
MyViewController *vc = [[MyViewController alloc] init];
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease];
nav.modalPresentationStyle = UIModalPresentationFormSheet;
[self.splitViewController presentModalViewController:nav animated:YES];
As I was finishing up my question, I realized I was calling becomeFirstResponder on my UITextView in viewWillAppear. If you change it to viewDidAppear it will work, which makes sense.

Resources