4

我有一个显示带有 UITextView 的视图的视图控制器,并且我想在键盘出现时调整视图的大小,以便 UITextView 不会被键盘覆盖。我几乎在所有情况下都能正常工作。据我所知,只有当视图控制器以 ModalPresentationStyleFormSheet 呈现并且仅以 LandscapeRight 方向呈现时,我仍然在 iPad 上看到了一些奇怪现象。

我的视图控制器 -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;
}

这在大多数情况下都有效。但是,当我的应用程序处于用户界面方向 LandscapeRight 时,我从 -boundsInWindow 获得的原点比它应该的要低很多。这可能是什么原因造成的?

感谢您的帮助!

4

3 回答 3

5

威尔的回答是正确的想法,但我不得不对其进行相当多的调整以使其正确

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)
    }
}
于 2015-08-21T22:49:58.223 回答
2

我想我已经找到了一个相当不错的答案。您可以使用convertRect:fromView:方法UIView来转换坐标系。

在 swift 代码中,UIKeyboardNotification 调用的选择器看起来像这样:

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
}
于 2015-01-03T07:56:45.617 回答
2

以下是我使用 iPad 表单处理键盘的方式:

- (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;
    }];
}

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);
}
于 2013-06-21T18:50:47.373 回答