Синхронизация анимаций в клавиатуреПоказать клавиатуруWillHide - аппаратная клавиатура и виртуальная клавиатура одновременно

Преамбула

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

Вот код, который я использую:

ШОУ:

- (void) keyboardWillShow:(NSNotification *)note {

    NSDictionary *keyboardAnimationDetail = [note userInfo];
    UIViewAnimationCurve animationCurve = [keyboardAnimationDetail[UIKeyboardAnimationCurveUserInfoKey] integerValue];
    CGFloat duration = [keyboardAnimationDetail[UIKeyboardAnimationDurationUserInfoKey] floatValue];

    NSValue* keyboardFrameBegin = [keyboardAnimationDetail valueForKey:UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];

    // working for hardware keyboard
    //UIViewAnimationOptions options = (UIViewAnimationOptions)animationCurve;

    // working for virtual keyboard
    UIViewAnimationOptions options = (animationCurve << 16);

    [UIView animateWithDuration:duration delay:0.0 options:options animations:^{
        textView.frame = CGRectMake(0, self.view.bounds.size.height - keyboardFrameBeginRect.size.height, self.view.bounds.size.width, -40);
    } completion:nil];

}

HIDE:

- (void) keyboardWillHide:(NSNotification *)note {

    NSDictionary *keyboardAnimationDetail = [note userInfo];
    UIViewAnimationCurve animationCurve = [keyboardAnimationDetail[UIKeyboardAnimationCurveUserInfoKey] integerValue];
    CGFloat duration = [keyboardAnimationDetail[UIKeyboardAnimationDurationUserInfoKey] floatValue];

    // hardware keyboard
    //UIViewAnimationOptions options = (UIViewAnimationOptions)animationCurve;

    // virtual keyboard
    UIViewAnimationOptions options = (animationCurve << 16);

    [UIView animateWithDuration:duration delay:0.0 options:options animations:^{
        textView.frame = CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, -40);
    } completion:nil];

}

Это отлично работает с виртуальной клавиатурой, но если клавиатураWillShow: или keyboardWillHide: вызывается в результате отсоединения или подключения аппаратной клавиатуры, анимация отстает. Я могу исправить это, изменив UIViewAnimationOptions

Заменить:

// Works with virtual keyboard
UIViewAnimationOptions options = (animationCurve << 16);

С

// working for firstResponder keyboard
UIViewAnimationOptions options = (UIViewAnimationOptions)animationCurve;

Но при этом теперь анимация virtualKeyboard отстает

Я понимаю, что анимация аппаратной клавиатуры не очень распространена, и это, возможно, не самая важная проблема, но мне нравится все, чтобы просто работать!

Примеры

VirtualKeyboard w/(animationCurve < 16) - РАБОТА

VirtualKeyboard w/ (animationCurve << 16)

VirtualKeyboard w/(UIViewAnimationOptions) animationCurve - BROKEN

VirtualKeyboard w/ (UIViewAnimationOptions)animationCurve

HardwareKeyboard w/(animationCurve < 16) - BROKEN

HardwareKeyboard w/ (animationCurve << 16)

HardwareKeyboard w/(UIViewAnimationOptions) animationCurve - WORKING

HardwareKeyboard w/ (UIViewAnimationOptions)animationCurve

Примечания

Чтобы имитировать аппаратную клавиатуру в симуляторе cmd + shft + k

Да, это реплицируется на реальном устройстве.

В случае, если вы этого хотите, здесь остальная часть моего кода, только для целей репликации

ДОБАВИТЬ ТЕКСТ ПРОСМОТР

textView = [UITextView new];
textView.layer.borderWidth = 10;
textView.layer.borderColor = [UIColor blackColor].CGColor;
textView.frame = CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, -40);
[self.view addSubview:textView];

UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init];
[tap addTarget:self action:@selector(handleTap:)];
[self.view addGestureRecognizer:tap];

// OBSERVE KEYBOARD
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];

РУЧКА:

- (void) handleTap:(UITapGestureRecognizer *)tap {
    NSLog(@"tapped");
    [textView resignFirstResponder];
}

Вопрос:

Что здесь происходит, и есть ли хороший способ получить согласованную анимацию, независимо от виртуальной/аппаратной клавиатуры?

Я понимаю, что это долго, спасибо за чтение!

Ответы

Ответ 1

Поскольку кривая анимации, которую Apple посылает вам в уведомлении на клавиатуре, не имеет соответствующего бита UIViewAnimationOption, вам нужно перейти к неблокированной анимации старой школы и использовать кривую напрямую:

NSTimeInterval duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [note.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
[UIView beginAnimations:@"SomeAnimationID" context:NULL];
[UIView setAnimationCurve:curve];
[UIView setAnimationDuration:duration];
// Animation code
[UIView commitAnimations];

Ответ 2

keyboardWillShow:

NSDictionary *info = [notification userInfo];
CGRect keyboardFrame = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval duration = [info[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [info[UIKeyboardAnimationCurveUserInfoKey] integerValue];

[self layoutIfNeeded];
[UIView animateWithDuration:duration delay:0 options:(curve << 20) animations:^{
    [self.keyboardConstraint setConstant:keyboardFrame.size.height];
    [self layoutIfNeeded];
} completion:nil];