27

我一直在做这样的事情来模仿旧版本 iOS 上的键盘动画。

CGRect keyboardBeginFrame;
[[note.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBeginFrame];
self.doneKeyboardButton.frame = CGRectMake(0, (keyboardBeginFrame.origin.y + keyboardBeginFrame.size.height) - 53, 106, 53);
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:self.doneKeyboardButton];

CGPoint newCenter = CGPointMake(self.doneKeyboardButton.superview.frame.origin.x + self.doneKeyboardButton.frame.size.width/2,
                                self.doneKeyboardButton.superview.frame.size.height - self.doneKeyboardButton.frame.size.height/2);

[UIView animateWithDuration:[[note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]-.02
                      delay:.0
                    options:[[note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]
                 animations:^{
                     self.contentView.frame = CGRectOffset(self.contentView.frame, 0, -TextFieldViewMovement);
                     self.doneKeyboardButton.center = newCenter;
                 }
                 completion:nil];

但是,这已停止在 iOS7 上运行。返回的值似乎不再完全正确,完成按钮不再完全模仿键盘显示动画。

4

7 回答 7

84

在 iOS 7 中,键盘使用了一种新的、未记录的动画曲线。虽然有些人注意到对动画选项使用未记录的值是可行的,但我更喜欢使用以下内容:

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

// work

[UIView commitAnimations];

虽然建议使用基于块的动画,但从键盘通知返回的动画曲线是UIViewAnimationCurve,而您需要传递给基于块的动画的选项是UIViewAnimationOptions。使用传统的 UIView 动画方法允许您直接将值通过管道输入。最重要的是,这将使用新的未记录动画曲线(整数值 7)并导致动画与键盘匹配。而且,它同样适用于 iOS 6 和 7。

于 2013-10-07T22:36:05.067 回答
23

我遇到了同样的问题,并设法让动画使用 iOS 7 的以下参数:

    [UIView animateWithDuration:0.5
                          delay:0
         usingSpringWithDamping:500.0f
          initialSpringVelocity:0.0f
                        options:UIViewAnimationOptionCurveLinear
                     animations:animBlock
                     completion:completionBlock];

编辑:这些值是通过调试获得的,并且可以随着新的 iOS 版本而改变。@DavidBeck 的答案在 iOS 7 中也适用于我,所以我在这里链接它。

于 2013-09-18T15:29:52.343 回答
10

Apple 在 iOS 7 中使用了一些值为 7 的未记录动画。

然而,声明UIViewAnimationCurve定义了 0 到 3 的值

typedef enum {
   UIViewAnimationCurveEaseInOut, // 0
   UIViewAnimationCurveEaseIn,
   UIViewAnimationCurveEaseOut,
   UIViewAnimationCurveLinear // 3
} UIViewAnimationCurve;

您需要基于块的UIViewAnimationOptions动画定义为

enum {
   // ...
   UIViewAnimationOptionCurveEaseInOut            = 0 << 16,
   UIViewAnimationOptionCurveEaseIn               = 1 << 16,
   UIViewAnimationOptionCurveEaseOut              = 2 << 16,
   UIViewAnimationOptionCurveLinear               = 3 << 16,

   UIViewAnimationOptionTransitionNone            = 0 << 20,
   // ...
};

似乎 Apple 为动画曲线(20 - 16 = 4)保留了 4 位,它允许从 0 到 15 的值(因此可能有更多未记录的值)。

有了这些知识,您可以通过将其移动大约 16 位来简单地将其UIViewAnimationCurve转换为。UIViewAnimationOptions在您的示例中,这意味着:

options:[[note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue] << 16
于 2013-12-25T02:46:51.237 回答
7

您可以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

于 2014-09-24T09:50:59.503 回答
0

这对我来说效果很好......显示键盘时会捕获持续时间。我知道对选项进行硬编码意味着它将来可能会中断,但它适用于 7 和 8。这对我们现在来说已经足够了......

[UIView animateWithDuration:self.animationDuration
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseInOut
                 animations:^{
                     [self.view layoutIfNeeded]; completion:^(BOOL finished) {
                     if (finished)
                     {
                         if (completion)
                             completion();
                     }
                 }];
于 2015-01-23T22:53:40.090 回答
0

如果您打算在工具栏中添加按钮(类似于移动 Safari 所做的那样),您可以只使用该属性inputAccessoryView(两者兼有UITextFieldUITextView并省去所有麻烦。这个隐藏的宝石鲜为人知,我很高兴我偶然发现了它。

它适用于 iOS 6 和 iOS 7,我在我的应用程序Routie中使用它。

于 2013-10-27T23:07:14.963 回答
0

iOS 10+
斯威夫特 5

更现代的替代方案(iOS 10+ 和 Swift)是使用UIViewPropertyAnimator,它不仅接受UIView.AnimationCurve而且是更现代的动画师。

您很可能会使用UIResponder.keyboardAnimationCurveUserInfoKey,我们将其视为NSNumber. 此密钥的文档是(Apple 自己的符号,不是我的):

public class let keyboardAnimationCurveUserInfoKey: String // NSNumber of NSUInteger (UIViewAnimationCurve)

使用这种方法,我们可以消除任何猜测,即插即用:

if let kbDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber,
    let kbTiming = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber, // doc says to treat as NSNumber
    let timing = UIView.AnimationCurve.RawValue(exactly: kbTiming), // takes an NSNumber
    let curve = UIView.AnimationCurve(rawValue: timing) // takes a raw value {
    let duration = kbDuration.doubleValue
    let animator = UIViewPropertyAnimator(duration: duration, curve: curve) {
        // add animations
    }
    animator.startAnimation()
}
于 2020-06-18T16:34:13.970 回答