2011-09-06 6 views
41

El UIKeyboardAnimationCurveUserInfoKey tiene un valor de UIViewAnimationCurve. ¿Cómo lo convierto al valor UIViewAnimationOptions correspondiente para usar con el argumento options del +[UIView animateWithDuration:delay:options:animations:completion:]?iOS: ¿Cómo convertir UIViewAnimationCurve a UIViewAnimationOptions?

// 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; 

Obviamente, podría crear un método simple categoría con una declaración switch, así:

// 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 

Pero, ¿hay una manera mejor/más fácil?

Respuesta

29

Podría decirse que puede tomar su primera solución y convertirla en una función en línea para ahorrarse el impulso de la pila. Es un condicional tan estricto (con uniones constantes, etc.) que debería compilarse en una pequeña pieza de ensamblaje.

Editar: por @ Matt, aquí tienes (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 
     } 
    } 
} 
+0

¿Cómo hago eso? Pensé que LLVM convierte automáticamente los métodos Objective-C en funciones en línea cuando es posible. – ma11hew28

+0

Parece que alguien más ya respondió su pregunta: http://stackoverflow.com/questions/8194504/does-llvm-convert-objective-c-methods-to-inline-functions –

+0

Agregué la versión en línea a mi respuesta. –

42

El método de categoría que sugiere es la forma "correcta" de hacerlo; no necesariamente tiene la garantía de que esas constantes mantengan su valor. De su análisis de cómo están definidas, sin embargo, parece que sólo podría hacer

animationOption = animationCurve << 16; 

... posiblemente con un yeso para NSUInteger y luego a UIViewAnimationOptions, si el compilador se siente como quejarse de eso.

+8

Recomiendo que guarda con algo como 'NSAssert (UIViewAnimationCurveLinear << == 16 UIViewAnimationOptionCurveLinear, @ "aplicación inesperada de UIViewAnimationCurve");' – lhunath

+0

@lhunath 7 se utiliza para animación de teclado y es privado. Pero pasó con userInfo desde el teclado. – Andy

11

Un problema con la solución basada interruptor es que no asume ninguna combinación Sin embargo, la práctica muestra que puede haber situaciones en las que la suposición no se cumple. Una instancia que encontré es (al menos en iOS 7) cuando obtiene las animaciones de teclado para animar su contenido junto con la aparición/desaparición del teclado.

Si escuchas a los keyboardWillShow:keyboardWillHide: o notificaciones, y luego obtener la curva del teclado anuncia que va a utilizar, por ejemplo:

UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; 

es muy probable que obtener el valor 7. Si pasa eso en la función/método de conmutación, no obtendrá una traducción correcta de ese valor, lo que dará como resultado un comportamiento de animación incorrecto.

La respuesta de Noah Witherspoon devolverá el valor correcto. La combinación de las dos soluciones, es posible escribir algo como:

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

La advertencia aquí, como se ha señalado por Noah también, es que si Apple cambia nunca las enumeraciones, donde los dos tipos ya no se corresponden, entonces esta función se romperá. La razón para usarlo de todos modos, es que la opción basada en el conmutador no funciona en todas las situaciones que puede encontrar hoy en día, mientras que sí lo hace.

+0

Si obtiene un valor de 7 para UIKeyboardAnimationCurveUserInfoKey, eso suena como un error. La documentación indica que el valor es una UIViewAnimationCurve. UIViewAnimationCurve se define como NS_ENUM, no como [NS_OPTIONS] (http://nshipster.com/ns_enum-ns_options/). Por lo tanto, los únicos valores posibles son 0, 1, 2 y 3. Cualquier otro valor no tiene sentido. UIViewAnimationOption, por otro lado, se define como NS_OPTIONS, y puede tener aproximadamente 32,000 valores diferentes. Ni siquiera la solución de Noah puede manejar un valor de 7, simplemente lo tratará como si se hubiera pasado UIViewAnimationCurveLinear. – Senseful

13

En Swift se puede hacer

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