Подтвердить что ты не робот

Клавиатура "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 полностью забыла. > : |

4b9b3361

Ответ 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.