在 keyboardWillShow 和 keyboardWillHide 中同步动画 -- 硬件键盘和虚拟键盘同时存在

15

前言

我有一个应用程序,其中包含一个聊天部分,我正在将键盘隐藏和显示的动画与聊天输入框的上升和下降同步。

这是我使用的代码:

SHOW:

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

}

隐藏:

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

}
这在虚拟键盘上效果很好,但如果由于连接或断开硬件键盘而调用keyboardWillShow:或keyboardWillHide:,则动画会出现延迟。我可以通过更改UIViewAnimationOptions来解决这个问题。 替换为:
// Works with virtual keyboard
UIViewAnimationOptions options = (animationCurve << 16);

使用:

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

但是现在,虚拟键盘的动画出现了延迟。

我知道硬件键盘动画并不常见,也可能不是最重要的问题,但我希望一切都能正常工作!

示例

VirtualKeyboard w/ (animationCurve << 16) -- 工作正常

VirtualKeyboard w/ (animationCurve << 16)

VirtualKeyboard w/ (UIViewAnimationOptions)animationCurve -- 出现故障

VirtualKeyboard w/ (UIViewAnimationOptions)animationCurve

HardwareKeyboard w/ (animationCurve << 16) -- 出现故障

HardwareKeyboard w/ (animationCurve << 16)

HardwareKeyboard w/ (UIViewAnimationOptions)animationCurve -- 工作正常

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

问题:

这里到底发生了什么,有没有一种好的方法可以获得一致的动画效果而不受虚拟/硬件键盘的影响?

我知道这篇文章很长,感谢您的阅读!


你的问题非常冗长且难以理解。尝试删减不必要的部分以提高可读性。 - Rafał Sroka
3
你建议我删掉什么?我想提供所有必要的代码和解释,让人们能够复制问题,并且我包括了可视化内容,以便人们可以看到我所说的内容。我知道它很长,但我认为这是大部分相关信息。 - Logan
1
@RicardoSánchez-Sáez - 我使用 Licecap,它非常棒!http://www.cockos.com/licecap/ - Logan
@Logan 看起来问题出在你指定动画曲线的方式上:正确的做法是 UIViewAnimationOptions options = animationCurve;,如果你要同时指定多个选项,请使用二进制 OR 运算符:options = op1 | op2 | op3; - Oleg Shanyuk
@OlegShanyuk 谢谢您的评论,但这与底层曲线问题以及它如何特别涉及数字/硬件键盘动画没有真正关联。 - Logan
显示剩余4条评论
2个回答

3

由于键盘通知中苹果发送给你的动画曲线没有对应的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];

感谢您的回答 Adlai,我目前有几件事情要处理,但我会在今天晚些时候尝试这个方法,并让您知道它是否解决了问题。 - Logan
嗨@Adlai,谢谢你的回答。我没能让它正常工作。你测试过吗,还是只是个想法? - Logan
我已经测试过了,对我来说运行得很好。你在使用什么动画代码? - Adlai Holler
我用你的代码替换了动画块,就像问题中所描述的那样。 - Logan
我确实这样做了,不幸的是,我仍然遇到同样的问题。 - Logan
显示剩余2条评论

-1

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接