iOS 7 - 键盘动画

48
我正在尝试理解iPhone 5模拟器上iOS 7.0中的新键盘动画。当键盘出现时,我想调整UITableView的大小,但我无法获取正确的动画细节。
当键盘出现或消失时,我正在使用NSNotification对象中的信息。
这是我的日志:
Move keyboard from {{0, 920}, {320, 216}} to {{0, 352}, {320, 216}}
 with duration: 0.400000
 and animation curve: 7

UIViewAnimationCurveEaseInOut = 0
UIViewAnimationCurveEaseIn = 1
UIViewAnimationCurveEaseOut = 2
UIViewAnimationCurveLinear = 3

动画曲线是一个未知的值,我该怎么办?


请检查以下链接是否能解决您的问题:https://dev59.com/I2gu5IYBdhLWcg3wdGwb - RK-
抱歉,我忘记写了,我正在使用一个带有UITableView子视图的UIViewController - Paul Warkentin
你期望有哪些动画细节? - RK-
2
@Krishnan 不是7,我想。 - David Snabel-Caunt
8个回答

72

iOS 7中,键盘使用了一个新的未记录的动画曲线。虽然有些人指出了使用动画选项的未记录值,但我更喜欢使用以下数值:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];

// work

[UIView commitAnimations];

虽然基于块的动画是推荐的,但从键盘通知返回的动画曲线是一个 UIViewAnimationCurve,而传递到基于块的动画的选项是一个 UIViewAnimationOptions。使用传统的 UIView 动画方法可以直接导入该值。 最重要的是,这将使用新的未记录的动画曲线(整数值为 7),并使动画与键盘匹配。而且,在 iOS 6 和 7 上同样有效。


2
UIKeyboardWillShowNotification 上运行得非常完美,但是当通过 UIKeyboardWillHideNotification 关闭键盘时,我的 UIView 似乎与键盘不同步。 - Piotr Tomasik
使用未记录的动画曲线是否合法?如果这样做,苹果会拒绝您的应用程序吗? - platypus
  1. 这很可能永远不会被苹果发现,但总的来说直接使用它是一个坏主意。
  2. 我们在这里没有直接使用它。我们天真地传递了我们得到的值。
- David Beck
4
我发现在iOS 7中,当键盘执行关闭动画时,它使用了一个未公开的UIViewAnimationCurve,整数值为6,而不是通过 UIKeyboardAnimationCurveUserInfoKey 报告的值7。这是个有些hacky的解决方案,但如果键盘正在关闭时使用[UIView setAnimationCurve:6]似乎可以保持UIView动画同步。 - Matt Bradley
我花了很长时间尝试让某个东西与键盘一起动画,但它从未看起来正确,直到我找到了这个答案。谢谢! - Orion Edwards
显示剩余3条评论

47

现在我找到了解决办法。动画从点 {0, 920} 开始,到达点 {0, 352}。问题在于 UITableView 对象的大小开始为 {160, 568},所以在动画开始前,我将 UITableView 的大小改为 {160, 920}

关于未知的动画曲线,我只需将参数设置为 animationCurve << 16,将其从视图动画曲线转换为视图动画选项。
这个值不等于线性、渐进、渐出和渐变动画曲线。

以下是我的代码:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(_keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

和:

- (void)keyboardWillShow:(NSNotification *)aNotification {
    NSDictionary *userInfo = aNotification.userInfo;

    //
    // Get keyboard size.

    NSValue *beginFrameValue = userInfo[UIKeyboardFrameBeginUserInfoKey];
    CGRect keyboardBeginFrame = [self.view convertRect:beginFrameValue.CGRectValue fromView:nil];

    NSValue *endFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardEndFrame = [self.view convertRect:endFrameValue.CGRectValue fromView:nil];

    //
    // Get keyboard animation.

    NSNumber *durationValue = userInfo[UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration = durationValue.doubleValue;

    NSNumber *curveValue = userInfo[UIKeyboardAnimationCurveUserInfoKey];
    UIViewAnimationCurve animationCurve = curveValue.intValue;

    //
    // Create animation.

    CGRect tableViewFrame = self.tableView.frame;
    bTableViewFrame.size.height = (keyboardBeginFrame.origin.y - tableViewFrame.origin.y);
    self.tableView.frame = tableViewFrame;

    void (^animations)() = ^() {
        CGRect tableViewFrame = self.tableView.frame;
        tableViewFrame.size.height = (keyboardEndFrame.origin.y - tableViewFrame.origin.y);
        self.tableView.frame = tableViewFrame;
    };

    //
    // Begin animation.

    [UIView animateWithDuration:animationDuration
                          delay:0.0
                        options:(animationCurve << 16)
                     animations:animations
                     completion:nil];
}

1
关于未知的动画曲线,我只需将参数设置为animationCurve << 16即可将其从视图动画曲线转换为视图动画选项。 - Brad Moore
1
Þ»ÀµƒÑþ£ïUIView.hõ©¡UIViewAnimationOptionCurveEaseInþÜäÕ«Üõ╣ëþñ║õ¥ïÒÇé - Sash Zats
9
这种事情真是太令人沮丧了。苹果到底怎么了?谢谢。 - secondcitysaint

12

您可以使用 animateWithDuration 块,并在其中设置曲线。这样做既干净又有效。

UIViewAnimationCurve curve = [[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
double duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

[UIView animateWithDuration:duration
                    delay:0
                  options:UIViewAnimationOptionBeginFromCurrentState 
               animations:^{
                 [UIView setAnimationCurve:curve];
                 /* ANIMATION HERE */
                 // don't forget layoutIfNeeded if you use autolayout
               }
               completion:nil];

愉快的编码!

更新

你可以使用我编写的简单UIViewController类别https://github.com/Just-/UIViewController-KeyboardAnimation,它可以帮助你处理键盘动画。


5

使用UIKeyboardWillChangeFrameNotification,因为一些国际键盘(如中文键盘)在使用过程中会改变高度。此外,这段代码可以正确地获取键盘高度,即使在横屏模式下也是如此。(注意:下面的代码适用于自动布局

//set your observer, in a method like viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];

- (void)keyboardWillChange:(NSNotification *)notification {
    CGRect initialRect = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGFloat initialHeight = self.view.frame.size.height - [self.view convertRect:initialRect fromView:nil].origin.y;
    CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGFloat newHeight = self.view.frame.size.height - [self.view convertRect:keyboardRect fromView:nil].origin.y;
    //set your constraints here, based on initialHeight and newHeight, which are the heights of the keyboard before & after animation.
    [self.contentView setNeedsUpdateConstraints];
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.contentView layoutIfNeeded];
    [UIView commitAnimations];
}

1
干净。Swift版本在这里https://dev59.com/VmAf5IYBdhLWcg3wMwQ9 - SwiftArchitect

4
要使用与键盘相同的动画效果,必须使用未经记录的曲线选项。
- (void)keyboardWillHide:(NSNotification *)notification {
    NSDictionary *userInfo = [notification userInfo];

    CGRect rect = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    NSTimeInterval animationDuration = [[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    NSInteger curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue] << 16;

    [UIView animateWithDuration:animationDuration delay:0.0 options:curve animations:^{

    } completion:nil];
}

我发现其实animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:方法是在iOS7和iOS8中所有动画都使用的新方法。只需设置正确的持续时间、阻尼和速度,您就可以获得相同的效果,甚至可以更改速度/时间。


2
在Swift 4中,
添加键盘通知的观察者:
  • UIKeyboardDidShowNotification
  • UIKeyboardDidHideNotification
通过
NSNotificationCenter.defaultCenter().addObserver(_ observer: Any, 
        selector aSelector: Selector, 
        name aName: NSNotification.Name?, 
        object anObject: Any?)

使用选择器实现键盘动画的 UI 动画。为了创建有效的曲线值,我们需要将 UIResponder.keyboardAnimationCurveUserInfoKey 左移 << 16 位。

func keyboardWillShow(_ notification: Notification!) {
    if let info = notification.userInfo {
        let keyboardSize = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
        let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double 
        let curveVal = (info[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.intValue ?? 7 // default value for keyboard animation
        let options = UIView.AnimationOptions(rawValue: UInt(curveVal << 16))
        UIView.animate(withDuration: duration, delay: 0, options: options, animations: {
        // any operation to be performed
    }, completion: nil)
    }
}

1
在iOS 13中,您处于隐式动画状态,因此只需在通知处理程序内修改布局即可使用正确的持续时间和曲线进行动画。

0

注册通知:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

通过对视图的frame.origin.y进行动画更改来响应。

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

    NSDictionary *userInfo = aNotification.userInfo;
    NSValue *endFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardEndFrame = [self.view convertRect:endFrameValue.CGRectValue fromView:nil];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[aNotification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[aNotification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
    [UIView setAnimationBeginsFromCurrentState:YES];

    CGRect searchButtonFrame = self.searchButton.frame;
    searchButtonFrame.origin.y = (keyboardEndFrame.origin.y - searchButtonFrame.size.height);
    self.searchButton.frame = searchButtonFrame;

    [UIView commitAnimations];
}

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