Клавиатура "WillShow" и "WillHide" против вращения - PullRequest
23 голосов
/ 17 марта 2012

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

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

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

Опять стандартная процедура. К сожалению, существует критическая ситуация, когда это преобразование не удается. Посмотрите, что происходит, когда iPhone поворачивается из портретной в альбомную, когда клавиатура развернута:

1) iOS автоматически запускает UIKeyboardWillHideNotification ; self.interfaceOrientation сообщается как портрет ; клавиатурыBound.height составляет 216,0 . Это имеет смысл . Зачем? Поскольку обработчику уведомлений предоставляется возможность «очистить», прежде чем представление переключится в альбомный режим.

2) iOS автоматически запускает UIKeyboardWillShowNotification ; self.interfaceOrientation сообщается как портрет ; клавиатура Bounds.height составляет 480,0 . Это НЕ имеет смысла . Почему бы и нет? Поскольку обработчик уведомлений выполнит свою работу, думая, что высота клавиатуры составляет 480.0!

Apple бросила мяч на этот раз, или я что-то не так делаю?

Обратите внимание, что прослушивание вместо UIKeyboard Did ShowNotification не является допустимым решением, поскольку оно значительно ухудшает восприятие пользователем. Зачем? Потому что анимация моих изменений в представлении после анимации развертывания клавиатуры ... ну, выглядит довольно ужасно.

Кому-нибудь удалось добиться, чтобы авторотация работала идеально, пока клавиатура развернута? Похоже, взрыв хаоса, который Apple полностью упустил из виду. >: |

Ответы [ 7 ]

55 голосов
/ 16 января 2013

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

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

Надеюсь, это должно быть то, что вы ищете:)

4 голосов
/ 07 октября 2013

Недавно я написал сообщение в блоге об этой проблеме, которую вы описали, и о том, как решить ее коротким и элегантным способом. Вот ссылка на пост: Синхронизация анимации вращения между клавиатурой и приложенным видом

Если вы не хотите углубляться в подробное объяснение, описанное в сообщении в блоге, вот краткое описание с примером кода:

Основной принцип состоит в том, чтобы использовать тот же метод, который используют все - наблюдение за уведомлениями клавиатуры для анимации прикрепленного вида вверх и вниз. Но в дополнение к этому вы должны отменить эти анимации, когда клавиатурные уведомления запускаются вследствие изменения ориентации интерфейса.

Пример поворота без отмены анимации, настраиваемой при изменении ориентации интерфейса: image

Пример поворота с отменой анимации при изменении ориентации интерфейса: image

- (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

2 голосов
/ 14 июня 2012

Я встретил ту же проблему.iOS дает мне неправильную ширину / высоту клавиатуры.В обработчике keyboardDidShow я использовал следующее:затем высоту (да, я такой наивный), я сделал обходной путь, как показано ниже:

if (keyboardSize.width < keyboardSize.height)
{
    // NOTE: fixing iOS bug: /6094530/klaviatura-willshow-i-willhide-protiv-vrascheniya
    CGFloat height = keyboardSize.height;
    keyboardSize.height = keyboardSize.width;
    keyboardSize.width = height;
}
0 голосов
/ 30 мая 2013

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

Используемый мной 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;
}

И все работало нормально.

0 голосов
/ 02 декабря 2012

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

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 голосов
/ 21 сентября 2012

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

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

Надеюсь, это поможет:)

0 голосов
/ 17 марта 2012

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

Если это не помогло, просто храните прямоугольник портретной и альбомной ориентации отдельно.Они хорошо документированы ;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...