Повторно реализовать методы анимации на основе блоков UIView с настраиваемой кривой плавности.

Отсутствие настраиваемых кривых плавности в методах анимации на основе блоков UIView приводит к базовой анимации, если требуются более сложные кривые.

Способ сделать это с категорией на CAKeyframeAnimation обсуждается в Как создать пользовательскую функцию плавности с помощью Core Animation?.

Чтобы мой код оставался чистым и удобным для сопровождения, я хотел бы сделать еще один шаг и повторно реализовать блочные методы UIView и включить блок, описывающий функцию кривой плавности. результирующая категория на UIView будет выглядеть примерно так:

+ (void)animateWithDuration:(NSTimeInterval)duration easingCurveFunction:(double(^)(double))function  animations:(void (^)(void))animations;

Кто-нибудь знает, как Apple реализует свои методы анимации на основе блоков?


person andersfrank    schedule 22.09.2012    source источник
comment
Похоже, вы можете переопределить метод делегата слоя -actionForKey:forLayer: (или как он там называется), чтобы обеспечить правильную анимацию всякий раз, когда изменение свойства производится из переданного блока анимации... Вот с чего я бы начал в любом случае   -  person nielsbot    schedule 22.09.2012
comment
Ознакомьтесь с github.com/zrxq/UIView-EasingFunctions.   -  person zrslv    schedule 30.06.2013


Ответы (2)


Я не уверен в создании блочного метода, но я обнаружил, что довольно простой способ реализовать пользовательскую функцию плавности и по-прежнему использовать блочную анимацию — это переопределить метод слоя addAnimation:(CAAnimation *)anim forKey:(NSString *)key и заменить его другой функцией плавности. для любого вида, который вы хотите анимировать.

Для начала создайте подкласс CALayer и добавьте следующий метод...

// CustomViewLayer.m

#import "CustomViewLayer.h"

@implementation CustomViewLayer

- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key
{
    if ([anim isKindOfClass:[CABasicAnimation class]]) {

        // intercept the animation and insert your own easing function
        int x1 = 0.250;
        int y1 = 1.185;
        int x2 = 0.210;
        int y2 = 1.000;
        CAMediaTimingFunction *func = [CAMediaTimingFunction functionWithControlPoints:x1 :y1 :x2 :y2];
        anim.timingFunction = func;    
    }

    [super addAnimation:anim forKey:key];
}

@end

В своем подклассе представления убедитесь, что вы возвращаете пользовательский класс слоя...

// CustomView.m

#import "CustomView.h"
#import "CustomViewLayer.h"

@implementation CustomView

+ (Class)layerClass
{
    return [CustomViewLayer class];
}

@end

Затем вы можете использовать стандартные методы анимации на основе блоков, такие как...

[UIView animateWithDuration:0.3 animations:^{
    [customView setFrame:newFrame];
}];

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

Наконец, замечательный инструмент для простого создания и тестирования функций плавности можно найти здесь: http://matthewlein.com/ceaser/

person lucien    schedule 31.05.2013

Я не знаю, как Apple реализует свои блочные методы, но, прочитав исходный код BlocksKit, я понял, что реализовать метод, который вы упомянули, вам, вероятно, потребуется:

  1. Объявите категорию UIView, такую ​​как UIView (блок)
  2. В категории добавьте свойство NSTimer для запуска/отмены таймера с заданной продолжительностью.
  3. В категории добавьте свойство блока, чтобы сохранить код блока easingCurveFunction.
  4. В категории добавьте еще один блок, чтобы сохранить код блока анимации.
  5. В вашем блочном методе установите таймер, сохраните код блоков в свойствах
  6. Когда сработает таймер, запустите блок easingCurveFunction и блок анимации, так как вы держите их в свойствах

На самом деле я следовал этой практике, когда добавлял свои собственные блочные методы в классы Apple.

person Chris Chen    schedule 22.09.2012
comment
Проблема в том, что мы вообще не используем анимацию, предоставляемую CoreAnimation... Это будет работать, но потребует, чтобы основной поток не выполнял никакой тяжелой работы или вообще никакой работы... было бы здорово использовать GPU и CoreAnimation в полной мере. - person hfossli; 06.12.2012