Подтвердить что ты не робот

IOS: Как преобразовать UIViewAnimationCurve в UIViewAnimationOptions?

UIKeyboardAnimationCurveUserInfoKey имеет значение UIViewAnimationCurve. Как преобразовать его в соответствующее значение UIViewAnimationOptions для использования с аргументом options +[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, например:

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

Но есть ли еще более простой/лучший способ?

4b9b3361

Ответ 1

Возможно, вы можете принять свое первое решение и сделать его встроенной функцией, чтобы сэкономить себе стек. Это такой жесткий условный (постоянный и т.д.), Который он должен скомпилировать в довольно крошечный кусок сборки.

Изменить: Per @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;
  }
}

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

Ответ 2

Метод категории, который вы предлагаете, - это "правильный" способ сделать это - у вас нет гарантии того, что эти константы сохраняют свою ценность. От взгляда на то, как они определены, однако, кажется, вы могли просто сделать

animationOption = animationCurve << 16;

... возможно, с приведением в NSUInteger, а затем в UIViewAnimationOptions, если компилятор чувствует, что жалуется на это.

Ответ 3

В Swift вы можете сделать

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

Ответ 4

Проблема с решением на основе коммутатора заключается в том, что он не предполагает, что никакая комбинация параметров никогда не будет передаваться. Практика показывает, что могут быть ситуации, когда предположение не выполняется. Один экземпляр, который я нашел, - это (по крайней мере, на iOS 7), когда вы получаете анимацию клавиатуры для анимации вашего контента вместе с появлением/исчезновением клавиатуры.

Если вы прослушаете уведомления keyboardWillShow: или keyboardWillHide:, а затем получите кривую, которую объявляет клавиатура, например:

UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

вы, вероятно, получите значение 7. Если вы передадите это в функцию/метод switch, вы не получите правильный перевод этого значения, что приведет к неправильному поведению анимации.

Ответ Ноа Уизерспуна вернет правильное значение. Объединив два решения, вы можете написать что-то вроде:

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

Оговорка здесь, как отметил Ной, также заключается в том, что если Apple когда-либо изменяет перечисления, где эти два типа больше не соответствуют, то эта функция будет ломаться. Причина, по которой это все равно, заключается в том, что опция на основе коммутатора не работает во всех ситуациях, с которыми вы можете столкнуться сегодня, в то время как это делает.