2011-09-06 5 views
41

Il UIKeyboardAnimationCurveUserInfoKey ha un valore UIViewAnimationCurve. Come faccio a convertirlo nel valore UIViewAnimationOptions corrispondente per l'utilizzo con l'argomento options di +[UIView animateWithDuration:delay:options:animations:completion:]?iOS: Come convertire UIViewAnimationCurve in 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; 

Ovviamente, ho potuto creare un semplice metodo di categoria con una dichiarazione switch, in questo modo:

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

Ma, c'è un modo ancora più facile/migliore?

risposta

29

Probabilmente puoi prendere la tua prima soluzione e renderla una funzione incorporata per risparmiare te stesso. È un condizionale talmente rigido (costante, ecc.) Che dovrebbe essere compilato in un piccolo pezzo di assemblaggio.

Edit: Per @ Matt, qui si va (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

Come faccio? Pensavo che LLVM converta automaticamente i metodi Objective-C in funzioni inline quando possibile. – ma11hew28

+0

Sembra che qualcun altro abbia già risposto alla tua domanda: http://stackoverflow.com/questions/8194504/does-llvm-convert-objective-c-methods-to-inline-functions –

+0

Ho aggiunto la versione inline alla mia risposta. –

42

Il metodo di categoria che suggerisci è il modo "giusto" per farlo: non è necessariamente garantito che tali costanti mantengano il loro valore. Guardando come sono definiti, anche se, a quanto pare si può solo fare

animationOption = animationCurve << 16; 

... possibilmente con un cast di NSUInteger e poi a UIViewAnimationOptions, se il compilatore sembra lamentarsi di questo.

+8

vi consiglio di guardia che con qualcosa come 'NSAssert (UIViewAnimationCurveLinear << == 16 UIViewAnimationOptionCurveLinear, @ "l'attuazione di imprevisto UIViewAnimationCurve");' – lhunath

+0

@lhunath 7 viene utilizzato per animazione della tastiera ed è privato. Ma passato con userInfo dalla tastiera. – Andy

11

Un problema con la soluzione basata interruttore è che si assume nessuna combinazione di opzioni saranno mai passate. La pratica mostra però che ci possono essere situazioni in cui l'ipotesi non regge. Un'istanza che ho trovato è (almeno su iOS 7) quando ottieni le animazioni della tastiera per animare i tuoi contenuti insieme all'aspetto/scomparsa della tastiera.

Se si ascoltano i keyboardWillShow: o keyboardWillHide: notifiche, e quindi ottenere la curva della tastiera annuncia utilizzerà, ad esempio:

UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; 

è molto probabile che ottenere il valore 7. Se si passa che in la funzione/metodo dello switch, non si otterrà una traduzione corretta di quel valore, con conseguente comportamento di animazione errato.

La risposta di Noah Witherspoon restituirà il valore corretto. Combinando le due soluzioni, si potrebbe scrivere qualcosa di simile:

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

L'avvertimento qui, come notato da Noah anche, è che se Apple cambia mai le enumerazioni in cui i due tipi non corrispondono più, allora questa funzione si romperà. La ragione per usarlo comunque è che l'opzione basata su switch non funziona in tutte le situazioni che potresti incontrare oggi, mentre ciò avviene.

+0

Se si ottiene un valore di 7 per UIKeyboardAnimationCurveUserInfoKey, sembra un bug. La documentazione afferma che il valore è un UIViewAnimationCurve. UIViewAnimationCurve è definito come NS_ENUM, non [NS_OPTIONS] (http://nshipster.com/ns_enum-ns_options/). Pertanto, gli unici valori possibili sono 0, 1, 2 e 3. Qualsiasi altro valore non ha significato. UIViewAnimationOption, d'altra parte, è definito come NS_OPTIONS e può avere circa 32.000 valori diversi. Nemmeno la soluzione di Noah può gestire un valore di 7, lo tratterà semplicemente come se fosse passata UIViewAnimationCurveLinear. – Senseful

13

In Swift si può fare

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