iOS:如何将UIViewAnimationCurve转换为UIViewAnimationOptions?

时间:2011-09-06 23:17:12

标签: objective-c ios uiview enums uiviewanimation

UIKeyboardAnimationCurveUserInfoKey的值为UIViewAnimationCurve。如何将其转换为相应的UIViewAnimationOptions值,以便与options的{​​{1}}参数一起使用?

+[UIView animateWithDuration:delay:options:animations:completion:]

显然,我可以使用// UIView.h typedef enum { UIViewAnimationCurveEaseInOut, // slow at beginning and end UIViewAnimationCurveEaseIn, // slow at beginning UIViewAnimationCurveEaseOut, // slow at end UIViewAnimationCurveLinear } UIViewAnimationCurve; // ... enum { // ... UIViewAnimationOptionCurveEaseInOut = 0 << 16, // default UIViewAnimationOptionCurveEaseIn = 1 << 16, UIViewAnimationOptionCurveEaseOut = 2 << 16, UIViewAnimationOptionCurveLinear = 3 << 16, // ... }; typedef NSUInteger UIViewAnimationOptions; 语句创建一个简单的类别方法,如下所示:

switch

但是,有更简单/更好的方法吗?

5 个答案:

答案 0 :(得分:43)

您建议的类别方法是“正确”的方法 - 您不一定能保证这些常量保持其价值。不过,看看它们是如何定义的,似乎你可以做到

animationOption = animationCurve << 16;

...如果编译器感到抱怨,可能会使用强制转换为NSUInteger然后转换为UIViewAnimationOptions。

答案 1 :(得分:32)

可以说你可以采用你的第一个解决方案并使其成为一个内联函数来节省堆栈推送。它是如此紧密的条件(常量限制等),它应该编译成一个非常小的组件。

编辑: 按@matt,你去(Objective-C):

static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCurve curve)
{
  switch (curve) {
    case UIViewAnimationCurveEaseInOut:
        return UIViewAnimationOptionCurveEaseInOut;
    case UIViewAnimationCurveEaseIn:
        return UIViewAnimationOptionCurveEaseIn;
    case UIViewAnimationCurveEaseOut:
        return UIViewAnimationOptionCurveEaseOut;
    case UIViewAnimationCurveLinear:
        return UIViewAnimationOptionCurveLinear;
  }
}

斯威夫特3:

extension UIViewAnimationOptions {
    init(curve: UIViewAnimationCurve) {
        switch curve {
            case .easeIn:
                self = .curveEaseIn
            case .easeOut:
                self = .curveEaseOut
            case .easeInOut:
                self = .curveEaseInOut
            case .linear:
                self = .curveLinear
        }
    }
}

答案 2 :(得分:17)

在Swift中你可以做到

extension UIViewAnimationCurve {
    func toOptions() -> UIViewAnimationOptions {
        return UIViewAnimationOptions(rawValue: UInt(rawValue << 16))
    }
}

答案 3 :(得分:11)

基于交换机的解决方案的一个问题是它假设没有传递任何选项组合。但实践表明,可能存在假设不成立的情况。我发现的一个实例是(至少在iOS 7上),当你获得键盘动画来动画你的内容以及键盘的外观/消失。

如果您收听keyboardWillShow:keyboardWillHide:通知,然后获取键盘宣布将使用的曲线,例如:

UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

您可能会获得值7.如果将其传递给切换函数/方法,则无法获得该值的正确转换,从而导致动画行为不正确。

Noah Witherspoon的回答将返回正确的值。结合这两种解决方案,您可以编写如下内容:

static inline UIViewAnimationOptions animationOptionsWithCurve(UIViewAnimationCurve curve)
{
    UIViewAnimationOptions opt = (UIViewAnimationOptions)curve;
    return opt << 16;
}

正如Noah所指出的,这里需要注意的是,如果Apple更改了两种类型不再对应的枚举,那么此函数将会中断。无论如何使用它的原因是基于开关的选项在你今天可能遇到的所有情况下都不起作用,而这样做。

答案 4 :(得分:2)

iOS 10 +
雨燕5

一种将UIView.AnimationCurve转换为UIView.AnimationOptions甚至可能无法实现的Swift替代方法是使用UIViewPropertyAnimator(iOS 10+),它接受UIView.AnimationCurve并且是比UIView.animate更现代的动画师。

您很有可能将使用UIResponder.keyboardAnimationCurveUserInfoKey,它返回一个NSNumber。该密钥的文档是(Apple自己的符号,不是我的):

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

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

if let kbTiming = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber, // doc says to unwrap as NSNumber
    let timing = UIView.AnimationCurve.RawValue(exactly: kbTiming), // takes an NSNumber
    let curve = UIView.AnimationCurve(rawValue: timing) { // takes a raw value
    let animator = UIViewPropertyAnimator(duration: duration, curve: curve) {
        // add animations
    }
    animator.startAnimation()
}