【问题标题】:Keyboard "WillShow" and "WillHide" vs. Rotation键盘“WillShow”和“WillHide”与旋转
【发布时间】:2012-04-02 12:52:15
【问题描述】:

我有一个视图控制器同时监听 UIKeyboardWillShowNotification 和 UIKeyboardWillHideNotification。这些通知的处理程序会调整视图的各个部分,这是标准过程。

以下代码用于从屏幕坐标转换键盘矩形:

CGRect keyboardBounds = [self.view convertRect:[keyboardBoundsValue CGRectValue] fromView:nil];

再次,标准程序。不幸的是,存在这种转换失败的危急情况。看看在部署键盘时 iPhone 从纵向旋转到横向会发生什么:

1) iOS 自动触发UIKeyboardWillHideNotification; self.interfaceOrientation 被报告为portrait; keyboardBounds.height 为 216.0这是有道理的。为什么?因为通知处理程序有机会在视图切换到横向模式之前“清理”。

2) iOS 自动触发UIKeyboardWillShowNotification; self.interfaceOrientation 被报告为portrait; keyboardBounds.height 为 480.0这没有意义。为什么不?因为通知处理程序会认为键盘的高度是 480.0!

Apple 是否在这个问题上丢了球,还是我做错了什么?

请注意,改为监听 UIKeyboardDidShowNotification 不是一个有效的解决方案,因为它会显着降低用户体验。为什么?因为在键盘部署动画发生后对视图的更改进行动画处理……嗯,看起来很糟糕。

在部署键盘时,有没有人设法让自动旋转完美地工作?这似乎是苹果完全忽视的混乱爆炸。 >:|

【问题讨论】:

  • 你用哪个 iOS 版本试试这个?

标签: iphone ios ipad keyboard autorotate


【解决方案1】:

可能有点晚了,但我刚刚遇到了同样的问题,并且有一个很好的解决方案,可以避免任何形式的变通(当然,除非苹果改变了事情)

基本上,当通知中心为UIKeyboardWillShowNotification(或任何其他通知)调用您的方法时,它为UIKeyboardFrameBeginUserInfoKey 提供的框架是在窗口的上下文中,而不是在您的视图中。这样做的问题是,无论设备方向如何,Windows 坐标系始终是纵向的,因此您会以错误的方式找到宽度和高度。

如果您想避免工作,只需将矩形转换为视图的坐标系(它会根据方向发生变化)。为此,请执行以下操作:

- (void) keyboardWillShow:(NSNotification *)aNotification
{
     CGRect keyboardFrame = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect convertedFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];

    ......
    /* Do whatever you want now with the new frame.
     * The width and height will actually be correct now
     */
    ......
}

希望这应该是你所追求的:)

【讨论】:

  • 注意将convertRect发送到正确的视图。
  • 非常感谢!倒置旋转中的 UIKeyboardFrameBeginUserInfoKey 似乎返回 {0,0} 原点。
【解决方案2】:

最近我写了一篇关于您所描述的确切问题的博客文章,以及如何用简短而优雅的方式解决它。这是帖子的链接:Synchronizing rotation animation between the keyboard and the attached view

如果您不想深入了解博文中描述的冗长解释,这里是带有代码示例的简短描述:

基本原理是使用每个人都使用的相同方法 - 观察键盘通知以使附加视图上下动画。但除此之外,当由于界面方向更改而触发键盘通知时,您必须取消这些动画。

在界面方向更改时没有自定义动画取消的旋转示例:

在界面方向更改时取消动画的旋转示例:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [[NSNotificationCenter defaultCenter]
            addObserver:self selector:@selector(adjustViewForKeyboardNotification:)
            name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]
            addObserver:self selector:@selector(adjustViewForKeyboardNotification:)
            name:UIKeyboardWillHideNotification object:nil];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    [[NSNotificationCenter defaultCenter]
            removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]
            removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    self.animatingRotation = YES;
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
    self.animatingRotation = NO;
}

- (void)adjustViewForKeyboardNotification:(NSNotification *)notification {
    NSDictionary *notificationInfo = [notification userInfo];

    // Get the end frame of the keyboard in screen coordinates.
    CGRect finalKeyboardFrame = [[notificationInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

    // Convert the finalKeyboardFrame to view coordinates to take into account any rotation
    // factors applied to the window’s contents as a result of interface orientation changes.
    finalKeyboardFrame = [self.view convertRect:finalKeyboardFrame fromView:self.view.window];

    // Calculate new position of the commentBar
    CGRect commentBarFrame = self.commentBar.frame;
    commentBarFrame.origin.y = finalKeyboardFrame.origin.y - commentBarFrame.size.height;

    // Update tableView height.
    CGRect tableViewFrame = self.tableView.frame;
    tableViewFrame.size.height = commentBarFrame.origin.y;

    if (!self.animatingRotation) {
        // Get the animation curve and duration
        UIViewAnimationCurve animationCurve = (UIViewAnimationCurve) [[notificationInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
        NSTimeInterval animationDuration = [[notificationInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

        // Animate view size synchronously with the appearance of the keyboard. 
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:animationDuration];
        [UIView setAnimationCurve:animationCurve];
        [UIView setAnimationBeginsFromCurrentState:YES];

        self.commentBar.frame = commentBarFrame;
        self.tableView.frame = tableViewFrame;

        [UIView commitAnimations];
    } else {
        self.commentBar.frame = commentBarFrame;
        self.tableView.frame = tableViewFrame;
    }
}

这个答案也发布在类似的问题中:UIView atop the Keyboard similar to iMessage App

【讨论】:

    【解决方案3】:

    我遇到了同样的问题。 iOS 给了我不正确的键盘宽度/高度。我在keyboardDidShow 处理程序中使用了以下片段:

    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize keyboardSize2 = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    LogDbg(@"keyboard size: frameBegin=%@; frameEnd=%@", NSStringFromCGSize(keyboardSize), NSStringFromCGSize(keyboardSize2));
    

    对于 iPad 的纵向和横向模式,我分别得到了:

    2012-06-14 04:09:49.734 -[LoginViewController keyboardDidShow:] 132 [DBG]:keyboard size: frameBegin={768, 264}; frameEnd={768, 264}
    2012-06-14 04:10:07.971 -[LoginViewController keyboardDidShow:] 132 [DBG]:keyboard size: frameBegin={352, 1024}; frameEnd={352, 1024}
    

    猜测键盘的宽度应该大于高度(是的,我太天真了)我做了如下的解决方法:

    if (keyboardSize.width < keyboardSize.height)
    {
        // NOTE: fixing iOS bug: http://stackoverflow.com/questions/9746417/keyboard-willshow-and-willhide-vs-rotation
        CGFloat height = keyboardSize.height;
        keyboardSize.height = keyboardSize.width;
        keyboardSize.width = height;
    }
    

    【讨论】:

      【解决方案4】:

      好吧,试试看键盘宽度。如果它是您期望的值,那么我假设这些值只是简单地切换;)。 480 作为进入横向的键盘宽度是有意义的,这就是让我产生这种预感的原因。

      如果失败,只需分别存储纵向和横向矩形。他们是well documented ;)

      【讨论】:

      • 谢谢,但我想避免硬编码这些值。操作系统将键盘尺寸报告给正在运行的进程是有原因的。
      • 我认为它们不是简单地颠倒过来的吗?
      【解决方案5】:

      我知道这是一个非常晚的回复。现在只有我遇到这种情况并找到未回答的问题。所以我想我会分享我的解决方案。会有一些其他更好的方法,但下面的方法也可以解决这个问题。

      我使用的 KBKeyboardHandler 来自:UITextField: move view when keyboard appears

      我刚刚更改了我的代表如下:

      - (void)keyboardSizeChanged:(CGSize)delta
      {    
          CGRect frame = self.view.frame;    
          UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
          switch (interfaceOrientation) {
              case UIInterfaceOrientationPortrait:
                  frame.origin.y-=delta.height;
                  break;
              case UIInterfaceOrientationPortraitUpsideDown:
                  frame.origin.y+=delta.height;
                  break;
              case UIInterfaceOrientationLandscapeLeft:
                  frame.origin.x-=delta.height;
                  break;
              case UIInterfaceOrientationLandscapeRight:
                  frame.origin.x+=delta.height;
                  break;
              default:
                  break;
          }
          self.view.frame = frame;
      }
      

      它运行良好。

      【讨论】:

        【解决方案6】:

        这是我的解决方法:

        CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
        float keyboardHeight = self.interfaceOrientation == UIInterfaceOrientationPortrait ? keyboardSize.height : keyboardSize.width;
        

        希望这会有所帮助:)

        【讨论】:

          【解决方案7】:

          我使用以下代码来获取适用于所有旋转的键盘大小

          NSDictionary *info = [aNotification userInfo];
          if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
            kbHeight = [[NSNumber numberWithFloat:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.width] floatValue];
          else
            kbHeight = [[NSNumber numberWithFloat:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height] floatValue];
          NSLog(@"keyboard height = %F",kbHeight);
          

          然后,我使用状态栏方向(适用于 iPad 的第一个启动案例)测试方向,并将视图移动到所需的相对方向,以便为键盘腾出空间。这非常有效,如果键盘是可见的,那么它会重新定位到正确的旋转位置。

          UIDeviceOrientation orientation =  [UIApplication sharedApplication].statusBarOrientation;
          
          
          if (orientation == UIDeviceOrientationPortrait)
            {
            NSLog(@"Orientation: portrait");
            self.originalCenter = self.view.center;
            self.view.center = CGPointMake(self.originalCenter.x, self.originalCenter.y-kbHeight);
            }
          
          if (orientation == UIDeviceOrientationPortraitUpsideDown)
            {
            NSLog(@"Orientation: portrait upside down");
            self.originalCenter = self.view.center;
            self.view.center = CGPointMake(self.originalCenter.x, self.originalCenter.y+kbHeight);
            }
          
          if (orientation == UIDeviceOrientationLandscapeLeft)
            {
            NSLog(@"Orientation: landscape left");
            self.originalCenter = self.view.center;
            self.view.center = CGPointMake(self.originalCenter.x+kbHeight,self.originalCenter.y);
            }
          
          if (orientation == UIDeviceOrientationLandscapeRight)
            {
            NSLog(@"Orientation: landscape right");
            self.originalCenter = self.view.center;
            self.view.center = CGPointMake(self.originalCenter.x-kbHeight,self.originalCenter.y);
            }
          

          您可以在键盘消失时或通过 textFileDidEndEditing 函数将视图返回到其原始位置。

          【讨论】:

            猜你喜欢
            • 2011-09-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-17
            • 1970-01-01
            相关资源
            最近更新 更多