【问题标题】:How can I find portion of my view which isn't covered by the keyboard (UIModalPresenationStyleFormSheet)?如何找到键盘未覆盖的视图部分 (UIModalPresenationStyleFormSheet)?
【发布时间】:2012-12-10 17:45:29
【问题描述】:

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

我的视图控制器 -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 获得的原点比它应该的要低很多。这可能是什么原因造成的?

感谢您的帮助!

【问题讨论】:

    标签: ios keyboard modalviewcontroller screen-rotation uimodalpresentationstyle


    【解决方案1】:

    Will 的回答是正确的想法,但我不得不对其进行大量调整以使其正确

    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】:

      以下是我使用 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);
      }
      

      【讨论】:

      • 这对我很有效。我在其中发现的唯一错误是对于 UIInterfaceOrientationLandscapeLeft 或 UIInterfaceOrientationLandscapeRight,您仍应使用 keyboardSize.height,而不是 keyboardSize.width。 (在 iOS 7.0 iPad 模拟器上测试)
      • 由于某种原因设置 contentInsets 似乎没有做任何事情。你有一些示例代码可以显示这个 sn-p 工作吗?
      • @RizwanSattar 我还需要使用windowBounds.size.height,而不是windowBounds.size.width
      【解决方案3】:

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

      在 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
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多