Keyboard “WillShow” and “WillHide” vs. Rotation

2020-05-16 04:09发布

I've got a view controller listening for both UIKeyboardWillShowNotification and UIKeyboardWillHideNotification. The handlers for these notifications adjust various parts of the view, which is standard procedure.

The following code is used to convert the keyboard rect from screen coordinates:

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

Again, standard procedure. Unfortunately, there is a critical situation where this conversion fails. Look at what happens when an iPhone is rotated from portrait to landscape while the keyboard is deployed:

1) iOS automatically fires UIKeyboardWillHideNotification; self.interfaceOrientation is reported as portrait; keyboardBounds.height is 216.0. This makes sense. Why? Because the notification handler is given the chance to "clean up" before the view switches to landscape mode.

2) iOS automatically fires UIKeyboardWillShowNotification; self.interfaceOrientation is reported as portrait; keyboardBounds.height is 480.0. This does NOT make sense. Why not? Because the notification handler is going to do its work thinking that the height of the keyboard is 480.0!

Did Apple drop the ball on this one, or am I doing something wrong?

Please note that listening instead for UIKeyboardDidShowNotification is not a valid solution, because it significantly degrades the user experience. Why? Because animating my changes to the view after the keyboard deployment animation occurs is... well, pretty terrible-looking.

Has anyone managed to get autorotation working perfectly while the keyboard is deployed? It seems like an explosion of chaos that Apple has completely overlooked. >:|

7条回答
放我归山
2楼-- · 2020-05-16 05:08

I use the following code to get the size of the keyboard which works fine for all rotations

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);

I then test for the orientation using the status bar orientation (which works in the first launch case for the iPad) and shift the view in the relative direction needed to make space for the keyboard. This works perfectly, if the keyboard is visible then it relocates to the correct position on rotations.

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);
  }

You can return the view to its original position when the keyboard disappears or via a textFileDidEndEditing function.

查看更多
登录 后发表回答