0

我想知道是否有一种方法可以在应用程序中快速使用更多不同的计时功能。例如使用Robert Penner 的,许多工具包都公开了它们,我很惊讶 Apple 没有。

基本上是一种让基于块的命令与 UIView 中的 animateWithDuration:delay:options:animations:completion: 一样灵活的方法。

我想出了这个解决方案,很高兴知道是否有更好的选择。

//  UIView+CustomTimingFunction.h
#import <UIKit/UIKit.h>

typedef enum {
    CustomTimingFunctionDefault,
    CustomTimingFunctionLinear,
    CustomTimingFunctionEaseIn,
    CustomTimingFunctionEaseOut,
    ....
} CustomTimingFunction;

@interface UIView (CustomTimingFunction)

- (void)animateProperty:(NSString *)property from:(id)from to:(id)to withDuration:(NSTimeInterval)duration customTimingFunction:(CustomTimingFunction)customTimingFunction competion:(void (^)(void))competion;

@end

//  UIView+CustomTimingFunction.m

#import "UIView+CustomTimingFunction.h"

@implementation UIView (CustomTimingFunction)

- (void)animateProperty:(NSString *)property from:(id)from to:(id)to withDuration:(NSTimeInterval)duration customTimingFunction:(CustomTimingFunction)customTimingFunction competion:(void (^)(void))competion
{
    [CATransaction begin]; {
        [CATransaction setCompletionBlock:competion];

        if([property isEqualToString:@"frame"]){
            CGRect fromRect = [from CGRectValue];
            CGPoint fromPosition = CGPointMake(CGRectGetMidX(fromRect), CGRectGetMidY(fromRect));
            CGRect toRect = [to CGRectValue];
            CGPoint toPosition = CGPointMake(CGRectGetMidX(toRect), CGRectGetMidY(toRect));

            CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
            positionAnimation.timingFunction = [[self class] functionWithType:customTimingFunction];
            positionAnimation.fromValue = [NSValue valueWithCGPoint:fromPosition];
            positionAnimation.toValue = [NSValue valueWithCGPoint:toPosition];

            CABasicAnimation *boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"];
            boundsAnimation.timingFunction = [[self class] functionWithType:customTimingFunction];
            boundsAnimation.fromValue = from;
            boundsAnimation.toValue = to;

            CAAnimationGroup * group =[CAAnimationGroup animation];
            group.removedOnCompletion=NO;
            group.fillMode=kCAFillModeForwards;
            group.animations = @[positionAnimation,boundsAnimation];
            group.duration = duration;

            [self.layer addAnimation:group forKey:property];
        }else{
            CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:property];
            animation.duration = duration;
            animation.timingFunction = [[self class] functionWithType:customTimingFunction];
            animation.fillMode = kCAFillModeForwards;
            animation.removedOnCompletion = NO;
            animation.fromValue = from;
            animation.toValue = to;
            [self.layer addAnimation:animation forKey:animation.keyPath];
        }
    } [CATransaction commit];

}

+(CAMediaTimingFunction *)functionWithType:(CustomTimingFunction)type
{
    switch (type) {
        case CustomTimingFunctionDefault:
            return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
            break;
        case CustomTimingFunctionLinear:
            return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
            break;

        case CustomTimingFunctionEaseIn:
            return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
            break;
        case CustomTimingFunctionEaseOut:
            return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
            break;
        case CustomTimingFunctionEaseInOut:
            return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
            break;

        ....
    }

    NSLog(@"Couldn't find CustomTimingFunction, will return linear");
    return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
}

@end

谢谢!

4

0 回答 0