Current scenario:
Right now I am showing a UIViewController
using a segue
with the style Modal
and presentation Sheet
. This Modal gets its superview
bounds change, in order to have the dimensions I want, like this:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.view.superview.bounds = WHBoundsRect;
}
The only allowed orientations are UIInterfaceOrientationLandscapeLeft
and UIInterfaceOrientationLandscapeRight
. Since the Modal has some TextFields
and the keyboard would be over the Modal itself, I am changing its center
so it moves a bit to the top.
The problem:
What I am noticing right now, is that I am unable to work with the Y coordinate. In order for it move vertically (remember it's on landscape) I need to work with the X. The problem is that when it's UIInterfaceOrientationLandscapeLeft
I need to come with a negative X. And when it's UIInterfaceOrientationLandscapeRight
I need to come with a positive X. So it seems that the X/Y Coordinate System is "glued" to the top left corner while in Portrait and when an orientation occurs, it's still there:
What I have done
So I have something like this:
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
NSInteger newX = 0.0f;
if (orientation == UIInterfaceOrientationLandscapeLeft)
{
// Logic for calculating the negative X.
}
else
{
// Logic for calculating the positive X.
}
It works exactly like I want, but it seems a very fragile implementation. Am I missing something? Is this the expected behaviour?
I wrote a test project, you can find it here
Here is the interesting part, the modal view controller subclass code.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillAppear:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.view.superview.bounds = WHBoundsRect;
}
- (void)keyboardWillAppear:(NSNotification*)notification
{
CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
// Calculate keyboard frame in superview coordinates.
// Origin will be in the upper left corner of the superview, so keyboard will have a negative x origin.
CGRect keyboardFrameInSuperviewCoordinates = [self.view.superview convertRect:keyboardFrame fromView:nil];
NSLog(@"Superview bounds: %@", NSStringFromCGRect(self.view.superview.bounds));
NSLog(@"Keyboard frame in screen coordinates: %@", NSStringFromCGRect(keyboardFrame));
NSLog(@"Keyboard frame in superview coordinates: %@", NSStringFromCGRect(keyboardFrameInSuperviewCoordinates));
// The keyboard and the superview lay directly in a window, so we should do the math on window coordinates
// Converting to the superview system takes account of rotation, so now y is relative to current orientation
CGRect windowCoordinatesInSuperviewSystem = [self.view.superview convertRect:self.view.superview.window.bounds fromView:nil];
NSLog(@"Window frame in superview coords: %@", NSStringFromCGRect(windowCoordinatesInSuperviewSystem));
// We calculate for how much the superview is hidden by the keyboard
CGFloat hiddenPartHeight = CGRectGetMaxY(self.view.superview.bounds)-CGRectGetMinY(keyboardFrameInSuperviewCoordinates);
NSLog(@"Superview is hidden by keyboard for %.0f points", hiddenPartHeight);
// Now we just have to shift the superview frame to the top by 'hiddenPartHeight'.
// Last step: calculate new superview frame in super-superview coordinate system.
// To do that, we convert the superview frame relative to its coordinate system to super-superview coordinate system.
CGRect superviewNewFrameInItsOwnCoordinateSystem = CGRectOffset(self.view.superview.bounds, 0, -hiddenPartHeight);
CGRect superviewAbsoluteFrame = [self.view.superview convertRect:superviewNewFrameInItsOwnCoordinateSystem toView:self.view.superview.superview];
NSLog(@"Superview new frame in its own coords: %@", NSStringFromCGRect(superviewNewFrameInItsOwnCoordinateSystem));
NSLog(@"Superview new frame: %@", NSStringFromCGRect(superviewAbsoluteFrame));
self.view.superview.frame = superviewAbsoluteFrame;
}