Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate the bottom offset of a modal view on iPad?

When a user taps a UITextField, the keyboard will come up. I scroll up the UITextField to sit just above the keyboard. This is working fine on iPhone:

enter image description here

- (void) someWhere
{
    [[NSNotificationCenter defaultCenter] 
        addObserver:self
        selector:@selector(onKeyboardShow:)
        name:UIKeyboardWillShowNotification
        object:nil];
}

- (void) onKeyboardShow:(NSNotification *)notification
{
    CGRect keyboardRect = [[[notification userInfo] 
        objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue
    ];

    if (keyboardRect.size.height >= IPAD_KEYBOARD_PORTRAIT_HEIGHT) {
        self.containerView.y = self.containerView.y - keyboardRect.size.width;
    } else {
        self.containerView.y = self.containerView.y - keyboardRect.size.height;        
    }
}

However, it is broken on iPad. On iPad, modal view controllers can be presented as a sheet that takes up only a portion of the screen. You can see that there is a gap between the last UITextField and the keyboard on iPad.

enter image description here

UINavigationController* nav = [[UINavigationController alloc]
    initWithRootViewController:someRootViewController];
nav.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:nav animated:YES completion:nil];

I need to detect the offset of the modal view from the bottom of the screen and add that to the Y coordinate of the UITextField. This will make the UITextField flush with the top of the keyboard. Through some reverse engineering, I got the frame of the modal view by traversing undocumented view hierarchy:

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    // describe is a category function on UIView that prints out the frame
    [self.viewController.view.superview.superview.superview.superview describe];
}

x: 114.000000,
y: 192.000000,
w: 540.000000,
h: 620.000000

Finally, to get the offset of the modal view from the bottom of the screen, I do:

UIView* modalView = self.viewController.view.superview.superview.superview.superview;
// usage of self-explanatory UIView category methods
CGFloat bottomOffset = modalView.superview.height - (modalView.y + modalView.height);

To my chagrin, this only works in portrait mode. For some reason, the modal view's superview is always stuck with a width of 768 and height of 1024 no matter what orientation the iPad is in. So here is where I'm asking for help. How do I reliably get the offset of the modal view from the bottom of the screen, irregardless of the orientation, on iPad?

like image 315
Pwner Avatar asked Sep 13 '13 00:09

Pwner


1 Answers

I see two possible solutions:

  1. Use an inputAccessoryView to attach the text field to the keyboard automatically.

  2. Convert the keyboard rect to the superview of the containerView you're trying to move. You can then get its top Y value in the coordinates of the containerView's superview.

Something like:

CGRect rectInWindowCoordinates = [self.containerView.window convertRect:keyboardRect fromWindow:nil];
CGRect rectCoveredByKeyboard = [self.containerView.superview convertRect:rectInWindowCoordinates fromView:nil];
CGFloat top = CGRectGetMinY(rectCoveredByKeyboard);
self.containerView.y = top - self.containerView.frame.size.height;
like image 107
Jesse Rusak Avatar answered Oct 17 '22 22:10

Jesse Rusak