How can I find portion of my view which isn't covered by the keyboard (UIModalPresenationStyleFormSheet)?

霸气de小男生 提交于 2020-01-23 01:24:47

问题


I've got a view controller showing a view with a UITextView, and I want to resize the view when the keyboard appears so that the UITextView isn't covered by the keyboard. I have this working correctly in almost all cases. I'm still seeing some weirdness on the iPad, only when the view controller is presented in ModalPresentationStyleFormSheet, and only in LandscapeRight orientation, as far as I can tell.

Relevant parts of my view controller's -keyboardWillShow:

// We'll store my frame above the keyboard in availableFrame
CGRect availableFrame = self.view.frame;

// Find the keyboard size
NSDictionary *userInfo = [notification userInfo];
NSValue keyboardFrameScreenValue = userInfo[UIKeyboardFrameBeginUserInfoKey];
CGRect keyboardFrameScreen =  [keyboardFrameScreenValue CGRectValue];
CGRect keyboardFrame = [self.view convertRect:keyboardFrameScreen fromView:nil];
CGSize keyboardSize = keyboardFrame.size;

// Figure out how much of my frame is covered by the keyboard
CGRect screenBounds = [self.view convertRect:[UIScreen mainScreen].bounds
                                    fromView:nil];
CGRect myBoundsScreen = [self.view boundsInWindow]; // See below
CGFloat myBottom = myBoundsScreen.origin.y + myBoundsScreen.size.height;
CGFloat keyboardTop = screenBounds.size.height - keyboardSize.height;
CGFloat lostHeight = myBottom - keyboardTop;
availableFrame.size.height -= lostHeight;

-[UIView boundsInWindow]:

- (CGRect)boundsInWindow {
  UIInterfaceOrientation orientation =
    [UIApplication sharedApplication].statusBarOrientation;
  CGRect bounds = [self convertRect:self.bounds toView:self.window];
  if (UIInterfaceOrientationIsLandscape(orientation)) {
    // Swap origin
    CGFloat x = bounds.origin.y;
    bounds.origin.y = bounds.origin.x;
    bounds.origin.x = x;
    // Swap size
    CGFloat width = bounds.size.height;
    bounds.size.height = bounds.size.width;
    bounds.size.width = width;
  }

  return bounds;
}

This works, most of the time. When my app is in user interface orientation LandscapeRight though, the origin I get from -boundsInWindow is quite a bit lower than it should be. What could be causing this?

Thanks for any assistance!


回答1:


Will's answer was the right idea but I had to tweak it quite a bit to get it right

extension UIView {
    func heightCoveredByKeyboardOfSize(keyboardSize: CGSize) -> CGFloat {
        let frameInWindow = convertRect(bounds, toView: nil)
        guard let windowBounds = window?.bounds else { return 0 }

        let keyboardTop = windowBounds.size.height - keyboardSize.height
        let viewBottom = frameInWindow.origin.y + frameInWindow.size.height

        return max(0, viewBottom - keyboardTop)
    }
}



回答2:


Here's how I'm handling the keyboard with iPad form sheets:

- (void)UIKeyboardDidShowNotification:(NSNotification*)aNotification
{
    NSDictionary *userInfo = [aNotification userInfo];
    CGSize keyboardSize = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, [self.view heightCoveredByKeyboardOfSize:keyboardSize], 0.0);

    [UIView animateWithDuration:.25f animations:^{
        self.scrollView.contentInset = contentInsets;
        self.scrollView.scrollIndicatorInsets = contentInsets;
    }];
}

Category on UIView:

- (CGFloat)heightCoveredByKeyboardOfSize:(CGSize)keyboardSize
{
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    CGRect frameInWindow = [self convertRect:self.bounds toView:nil];
    CGRect windowBounds = self.window.bounds;

    CGFloat keyboardTop;
    CGFloat heightCoveredByKeyboard;

    //Determine height of the view covered by the keyboard relative to current rotation

    switch (orientation) {
        case UIInterfaceOrientationLandscapeLeft:
            keyboardTop = windowBounds.size.width - keyboardSize.width;
            heightCoveredByKeyboard = CGRectGetMaxX(frameInWindow) - keyboardTop;
            break;
        case UIInterfaceOrientationLandscapeRight:
            keyboardTop = windowBounds.size.width - keyboardSize.width;
            heightCoveredByKeyboard = windowBounds.size.width - frameInWindow.origin.x - keyboardTop;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            keyboardTop = windowBounds.size.height - keyboardSize.height;
            heightCoveredByKeyboard = windowBounds.size.height - frameInWindow.origin.y - keyboardTop;
            break;
        default:
            keyboardTop = windowBounds.size.height - keyboardSize.height;
            heightCoveredByKeyboard = CGRectGetMaxY(frameInWindow) - keyboardTop;
            break;
    }

    return MAX(0.0f,heightCoveredByKeyboard);
}



回答3:


I think I've found a pretty decent answer. You can use the convertRect:fromView: method on UIView to convert coordinate systems.

In swift code, the selector that UIKeyboardNotification calls look something like this:

func keyboardWasShown(notification: NSNotification) {
    let info = notification.userInfo!
    let keyboardRect = (info[UIKeyboardFrameEndUserInfoKey]! as NSValue).CGRectValue()

    // Convert the keyboard rect into the view controller's coordinate system
    // The fromView: nil means keyboardRect is in the main window's coordinate system
    let newSize = self.view.convertRect(keyboardRect, fromView: nil)

    // And then this is the part that gets covered!
    let keyboardCoveredHeight = self.view.bounds.height - newSize.origin.y
    // Note: you may have to use self.navigationController!.view.bounds.height if
    // you've wrapped your view in a navigation controller because this will 
    // include the height of the navigation bar

    // You can then adjust the content inset of the text view accordingly
    textView.scrollIndicatorInsets.bottom = keyboardCoveredHeight
    textView.contentInset.bottom = keyboardCoveredHeight
}


来源:https://stackoverflow.com/questions/13806282/how-can-i-find-portion-of-my-view-which-isnt-covered-by-the-keyboard-uimodalpr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!