Клавиатура "WillShow" и "WillHide" против вращения
У меня есть контроллер просмотра, который прослушивает как UIKeyboardWillShowNotification, так и UIKeyboardWillHideNotification. Обработчики для этих уведомлений настраивают различные части представления, что является стандартной процедурой.
Следующий код используется для преобразования прямоугольника клавиатуры из экранных координат:
CGRect keyboardBounds = [self.view convertRect:[keyboardBoundsValue CGRectValue] fromView:nil];
Опять стандартная процедура. К сожалению, существует критическая ситуация, когда это преобразование терпит неудачу. Посмотрите, что происходит, когда iPhone поворачивается с портрета на пейзаж при развертывании клавиатуры:
1) iOS автоматически запускает UIKeyboardWillHideNotification; self.interfaceOrientation сообщается как портрет; keyboardBounds.height - 216.0. Это имеет смысл. Зачем? Поскольку обработчику уведомлений предоставляется возможность "очистить" до того, как представление переключится в альбомный режим.
2) iOS автоматически запускает UIKeyboardWillShowNotification; self.interfaceOrientation сообщается как портрет; keyboardBounds.height - 480.0. Это не имеет смысла. Почему нет? Поскольку обработчик уведомлений собирается сделать свою работу, думая, что высота клавиатуры равна 480,0!
Яблоко бросает мяч на этот, или я делаю что-то неправильно?
Обратите внимание, что прослушивание вместо UIKeyboard Did ShowNotification не является допустимым решением, поскольку оно значительно ухудшает работу пользователя. Зачем? Поскольку анимация моих изменений в представлении после развертывания развертывания клавиатуры происходит... ну, довольно ужасно.
Кто-нибудь сумел получить автоматическую работу, отлично работающую при развертывании клавиатуры? Это похоже на взрыв хаоса, который Apple полностью забыла. > : |
Ответы
Ответ 1
Может быть, немного поздно, но я просто столкнулся с той же проблемой и имею хорошее решение для этого, которое позволяет избежать любых видов работы (если, конечно, яблоко не изменит ситуацию)
В принципе, когда центр уведомлений вызывает ваш метод для UIKeyboardWillShowNotification
(или любого другого уведомления), кадр, который он дает вам для UIKeyboardFrameBeginUserInfoKey
, находится в контексте окна, а не в вашем представлении. Проблема заключается в том, что система координат окон всегда находится на портрете, независимо от ориентации устройств, поэтому вы обнаруживаете ширину и высоту в обратном направлении.
Если вы хотите избежать своей работы, просто преобразуйте прямоугольник в систему координат вашего вида (что меняется в соответствии с ориентацией). Для этого сделайте следующее:
- (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
*/
......
}
Надеюсь, это должно быть то, что вам нужно:)
Ответ 2
Недавно я написал сообщение в блоге об этой точной проблеме, которую вы описали, и о том, как ее решить коротким и элегантным способом. Вот ссылка на сообщение: Синхронизация анимации вращения между клавиатурой и прикрепленным представлением
Если вы не хотите погружаться в длинное объяснение, описанное в блоге, здесь приводится краткое описание с примером кода:
Основным принципом является использование того же метода, который каждый использует - наблюдения за уведомлениями клавиатуры, чтобы оживить прикрепленное представление вверх и вниз. Но в дополнение к этому, вы должны отменить эти анимации, когда уведомления о клавиатуре запускаются из-за изменения ориентации интерфейса.
Пример вращения без отмены анимации при изменении ориентации интерфейса:
![59YGJ.png]()
Пример поворота с отменой анимации при изменении ориентации интерфейса:
![ahbhD.png]()
- (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 на клавиатуре, подобной 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 имеет смысл как ширину клавиатуры для перехода в ландшафт, что и дает мне эту догадку.
Если это не удается, просто сохраните портретные и ландшафтные прямоугольники отдельно. Они хорошо документированы;)
Ответ 5
Я знаю, что это очень поздний ответ. Теперь только я пришел к этой ситуации и нашел оставшийся без ответа вопрос. Поэтому я решил поделиться своим решением. Там будет другой лучший способ, но следующий способ также мы можем решить это.
KBKeyboardHandler, который я использовал, это: UITextField: переместить представление при появлении клавиатуры
Я просто изменил свой делегат следующим образом:
- (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.