48

我试图了解 iPhone 5 Simulator 上 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

动画曲线是未知值,怎么办?

4

8 回答 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。

于 2013-10-07T22:37:38.277 回答
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];
}
于 2013-09-24T07:51:03.407 回答
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

于 2014-09-24T09:51:35.693 回答
5

Use UIKeyboardWillChangeFrameNotification instead, because some international keyboards, like the Chinese keyboard, change height during use. Also this code gives you the correct heights for the keyboard, even in landscape mode. (Note: the code below is for Autolayout)

//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];
}
于 2014-08-04T00:39:27.307 回答
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 中完成所有动画的新方法。您只需设置正确的持续时间、阻尼和速度,您将获得相同的效果,但即使您也可以更改速度/时间。

于 2014-02-12T10:19:25.063 回答
2

在 Swift 4 中</p>

为键盘通知添加观察者:


  • UIKeyboardDidShowNotification
  • UIKeyboardDidHideNotification

通过

NSNotificationCenter.defaultCenter().addObserver(_ observer: Any, 
        selector aSelector: Selector, 
        name aName: NSNotification.Name?, 
        object anObject: Any?)

并实现选择器以使用键盘动画为 UI 设置动画。为了创建一个有效的曲线值,我们需要将 UIResponder.keyboardAnimationCurveUserInfoKey 移动 << 16 </p>

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)
    }
}
于 2019-04-02T08:21:58.470 回答
1

在 iOS 13 中,您处于隐式动画中,因此只需在通知处理程序中修改您的布局,它就会以正确的持续时间和曲线进行动画处理。

于 2020-04-17T19:41:09.447 回答
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];
}
于 2014-05-08T21:35:09.290 回答