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

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.

Related

UIPresentationController not calling containerViewWillLayoutSubviews until after display

I have a UIPresentationController displaying a side menu over the main view with a fixed width of 300. Then from the side menu the user can open a full screen modal view. When the modal view is dismissed the menu view fills the screen during the dismissal animation (this is wrong). At the end of the animation containerViewWillLayoutSubviews is called and the menu corrects it's width to 300.
I do implement frameOfPresentedViewInContainerView. I am also implementing shouldPresentInFullscreen returning NO on the menu view (though this seems to not affect anything I can really determine).
Why isn't containerViewWillLayoutSubviews called before the dismssal animation? How should I be maintaining the menu view's width when it is covered and revealed?
Thanks to riadhluke for directing me to UIPresentationController changes size when another view controller is displayed on top of it
My solution is in my menu's prepareForSegue
UIViewController *destination = [segue destinationViewController];
if (destination.modalPresentationStyle == UIModalPresentationFullScreen) {
destination.modalPresentationStyle = UIModalPresentationOverFullScreen;
}
Which forces fullscreen modal presentations to be Over full screen, which causes the menu not to be lost, and therefore not re laid out post dismissal animation.

Popping UIViewController causes previous UIViewControllers View to change position

I have a UINavigationController with a UIViewController set as it's rootController, it contains a background on its UIView using an image set just under the navBar. I then push onto the navigation controller a new UIViewController and when the back button is pushed, the previous controller looks different. Using the visual debugger I can see that the self.view has moved entirely down below the navBar where previously it was at the top. I have no idea and been racking my brains as to why this might be happening
-(void)pushIPhoneMessagingContactsController:(MessageContactsViewController *)contactsController{
self.selectorView.hidden = YES;
[self.navigationController pushViewController:contactsController animated:YES];
}
On the RootViewController (iPhoneMessagingNotificationsController)
-(void)viewWillAppear:(BOOL)animated{
self.selectorView.hidden = NO;
[[[self navigationItem] leftBarButtonItem] setTintColor:[UIColor blackColor]];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
if ([_displayType intValue] == MESSAGES_SHOWING) {
[self.notificationsViewController.view removeFromSuperview];
[self.contentView addSubview:_messagesViewController.view];
} else {
[self.messagesViewController.view removeFromSuperview];
[self.contentView addSubview:_notificationsViewController.view];
}
}
It seems the offending line was in the viewWillAppear method of the pushed UIViewController
self.navigationController.navigationBar.translucent = YES;
Somewhere else this navigationBar gets set as translucent:
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
and to make it solid colour again:
self.navigationController.navigationBar.shadowImage = nil;
self.navigationController.navigationBar.translucent = NO;
but this code seems to mess with the layout so perhaps there is another way to change the opacity of the navBar and statusBar without affecting the layout?
What you're currently trying to do is hide or show a selectorView which really only should appear for one specific view controller.
Here's an encapsulated way to solve this that makes your selectorView a part of the root view controller, removing the connection from other view controllers. They no longer have to know about it or hide it.
Add your selectorView to your rootViewController's navigation bar titleView. (You can do this in code, or drop it in Storyboard and add an IBOutlet for it.)
self.navigationItem.titleView = selectorView;
Now when you push another view controller, its title will replace your rootViewController's selectorView title (view). Your other view controllers don't need to know anything about that view.
This is a good design approach in general. Anytime you have a control that should only appear on one view controller's navigation bar, you want to make it a part of that view controller's navigationItem (titleView, or left/right bar button items.) iOS will display the control when it presents that view controller, and hide the control when that view controller is no longer the top view controller in the navigation controller stack.
As for the 64-pixel height issue, it's likely related to some complexity in the rootViewController hierarchy that shouldn't be there.
In iOS 7/8, a view's content, by default, appears under a translucent navigation bar. Apple freely managed this for you, by insetting the first view of the view hierarchy.
From your code, it appears that you're trying to "hide" or "show" the (un)selected viewController's view.
Each view controller should have a view it controls. A view controller shouldn't be trying to control other view controller's views, or adding other view controller's views to its own view hierarchy.
Here's Apple's recommended way to approach this. Use a containerView in your rootViewController. The whole purpose of a container view is to encapsulate a view controller within a view. As your selectorView changes which view to show, you have your container view transition from one view controller to the other. (If you're not familiar with how to do that, check out this answer.)
Pin the containerView to the rootViewController's view, so Auto Layout can size it for you.
Your view hierarchy now looks like view -> containerView, instead of view -> hidden view of unselected view controller, shown view of selected view controller. Apple can adjust the first view's inset, and nothing gets incorrectly offset (by the height of the navigation control).
Update:
This question talks about scrollViewInsets and how they can be set on a view-controller-by-view-controller basis. If you do have a view controller, and you don't want its content to appear under a bar, uncheck that box.
But the best way to handle this is to "standardize" your UI, so it isn't varying from view to view. Either make the bar always be translucent, or not always be translucent. This makes transitions less "jarring" for the users.

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

iOS: Apply view rotation to view controller under modal view

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

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.

Resources