2012-03-17 2 views
22

У меня есть контроллер просмотра, который прослушивает как UIKeyboardWillShowNotification, так и UIKeyboardWillHideNotification. Обработчики этих уведомлений настраивают различные части представления, что является стандартной процедурой.Клавиатура «WillShow» и «WillHide» против вращения

Следующий код используется для преобразования клавиатуры прямоугольник от координаты экрана:

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 ShowNotification недействительное решение, поскольку оно значительно ухудшает работу пользователя. Зачем? Поскольку анимация моих изменений в представлении после развертывания развертывания клавиатуры происходит ... ну, довольно ужасно.

Неужели кому-то удалось полностью автоматизировать работу, когда клавиатура развернута? Это похоже на взрыв хаоса, который Apple полностью забыла. >: |

+0

Какую версию iOS вы пытаетесь с этим? – Till

+0

5.1, 5.0 и 4.3.2 – Voobr

ответ

52

Может быть, немного поздно, но я просто запустить в тот же вопрос и иметь хорошее решение для него, что позволяет избежать каких-либо работ обходные (если, конечно, вещи изменения яблока)

В основном, когда уведомление центр вызывает ваш метод для 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 
    */ 
    ...... 
} 

Надеемся, что это должно быть то, что вы после :)

+0

Позаботьтесь о том, чтобы отправить 'convertRect' в правильный вид. – Nestor

+2

Спасибо большое! Кажется, что UIKeyboardFrameBeginUserInfoKey с переворотом в обратном направлении возвращает {0,0}. – Razvan

0

Хорошо, попробуйте взглянуть на ширину клавиатуры. Если это значение, которое вы ожидаете, я предполагаю, что значения просто переключаются;). 480 имеет смысл в качестве ширины клавиатуры для перехода в ландшафт, что и дает мне эту догадку.

Если это не удается, просто сохраните портретные и ландшафтные прямоугольники отдельно. Они well documented;)

+0

Спасибо, но я хотел бы избежать жесткого кодирования таких значений. Причина в том, что ОС сообщает о размерах клавиатуры для текущего процесса. – Voobr

+0

Я так понимаю, они не просто менялись тогда? – borrrden

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

Вот мой обходной путь:

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

Надеется, что это помогает :)

-1

Я использую следующий код, чтобы получить размер клавиатуры, которая работает отлично подходит для всех вращений

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.

0

Я это очень очень поздно ответ знаю. Теперь только я пришел к этой ситуации и нашел оставшийся без ответа вопрос. Поэтому я решил поделиться своим решением. Там будет другой лучший способ, но следующий способ также мы можем решить это.

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

И это работало отлично.

4

Недавно я написал сообщение в блоге об этой точной проблеме, которую вы описали, и о том, как ее решить коротким и элегантным способом.Вот ссылка на этот пост: 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

Смежные вопросы