web-dev-qa-db-fra.com

iOS: Comment convertir UIViewAnimationCurve en UIViewAnimationOptions?

UIKeyboardAnimationCurveUserInfoKey a une valeur UIViewAnimationCurve. Comment le convertir en valeur UIViewAnimationOptions correspondante à utiliser avec l'argument options de +[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;

Évidemment, je pourrais créer une méthode de catégorie simple avec une instruction switch, comme ceci:

// UIView+AnimationOptionsWithCurve.h

@interface UIView (AnimationOptionsWithCurve)
@end

// UIView+AnimationOptionsWithCurve.m

@implementation UIView (AnimationOptionsWithCurve)

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

@end

Mais, existe-t-il un moyen encore plus facile/meilleur?

47
ma11hew28

On peut soutenir que vous pouvez prendre votre première solution et en faire une fonction en ligne pour vous sauver la pile Push. C'est une condition tellement stricte (à constante constante, etc.) qu'elle devrait être compilée en un assez petit morceau d'assemblage.

Edit: Par @matt, c'est parti (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;
  }
}

Swift 3:

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

La méthode de catégorie que vous suggérez est la "bonne" façon de procéder: vous n'avez pas nécessairement la garantie que ces constantes conservent leur valeur. En regardant comment ils sont définis, cependant, il semble que vous pourriez simplement faire

animationOption = animationCurve << 16;

... éventuellement avec un transtypage en NSUInteger puis en UIViewAnimationOptions, si le compilateur a envie de s'en plaindre.

44
Noah Witherspoon

Dans Swift vous pouvez faire

extension UIViewAnimationCurve {
    func toOptions() -> UIViewAnimationOptions {
        return UIViewAnimationOptions(rawValue: UInt(rawValue << 16))
    }
}
18
Tomáš Linhart

Un problème avec la solution basée sur le commutateur est qu'elle suppose qu'aucune combinaison d'options ne sera jamais transmise. La pratique montre cependant qu'il peut y avoir des situations où l'hypothèse ne tient pas. Un exemple que j'ai trouvé est (au moins sur iOS 7) lorsque vous obtenez les animations du clavier pour animer votre contenu ainsi que l'apparence/la disparition du clavier.

Si vous écoutez le keyboardWillShow: ou keyboardWillHide: notifications, puis obtenez la courbe que le clavier annonce qu'il utilisera, par exemple:

UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

vous obtiendrez probablement la valeur 7. Si vous la transmettez à la fonction/méthode de commutation, vous n'obtiendrez pas une traduction correcte de cette valeur, ce qui entraînera un comportement d'animation incorrect.

La réponse de Noah Witherspoon renverra la valeur correcte. En combinant les deux solutions, vous pourriez écrire quelque chose comme:

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

La mise en garde ici, comme l'a également noté Noah, est que si Apple modifie jamais les énumérations où les deux types ne correspondent plus, alors cette fonction se cassera. La raison de l'utiliser de toute façon, c'est que L'option basée sur le commutateur ne fonctionne pas dans toutes les situations que vous pouvez rencontrer aujourd'hui, alors que cela fonctionne.

11
Antonio Nunes