linphone-iphone/Classes/Utils/CPAnimation/CPAnimationStep.m
Yann Diorcet b634a50283 Add NinePath lib
Continue chat stuff
Fix viewWillAppear without viewDidLoad called with UICompositeController
2012-07-06 17:43:46 +02:00

132 lines
3.5 KiB
Objective-C
Executable file

// Created by Yang Meyer on 26.07.11.
// Copyright 2011-2012 compeople AG. All rights reserved.
#import "CPAnimationStep.h"
@interface CPAnimationStep()
/** A temporary reverse queue of animation steps, i.e. from last to first.
It is created when the step is run, and is modified during the animation,
and is destroyed when the animation finishes. */
@property (nonatomic, strong) NSMutableArray* consumableSteps;
@end
@implementation CPAnimationStep
@synthesize delay, duration, step, options;
@synthesize consumableSteps;
#pragma mark overrides
#pragma mark construction
+ (id) after:(NSTimeInterval)delay animate:(AnimationStep)step {
return [self after:delay for:0.0 options:0 animate:step];
}
+ (id) for:(NSTimeInterval)duration animate:(AnimationStep)step {
return [self after:0.0 for:duration options:0 animate:step];
}
+ (id) after:(NSTimeInterval)delay for:(NSTimeInterval)duration animate:(AnimationStep)step {
return [self after:delay for:duration options:0 animate:step];
}
+ (id) after:(NSTimeInterval)theDelay
for:(NSTimeInterval)theDuration
options:(UIViewAnimationOptions)theOptions
animate:(AnimationStep)theStep {
CPAnimationStep* instance = [[self alloc] init];
if (instance) {
instance.delay = theDelay;
instance.duration = theDuration;
instance.options = theOptions;
instance.step = theStep;
}
return instance;
}
- (void)dealloc {
[step release];
[super dealloc];
}
#pragma mark action
// From http://stackoverflow.com/questions/4007023/blocks-instead-of-performselectorwithobjectafterdelay
+ (void) runBlock:(AnimationStep)block afterDelay:(NSTimeInterval)delay {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay), dispatch_get_current_queue(), block);
}
- (NSArray*) animationStepArray {
// subclasses must override this!
return [NSArray arrayWithObject:self];
}
- (void) runAnimated:(BOOL)animated {
if (!self.consumableSteps) {
self.consumableSteps = [[NSMutableArray alloc] initWithArray:[self animationStepArray]];
}
if (![self.consumableSteps count]) { // recursion anchor
[self.consumableSteps release];
self.consumableSteps = nil;
return; // we're done
}
void (^completionStep)(BOOL) = ^(BOOL animated){
[self.consumableSteps removeLastObject];
[self runAnimated:animated]; // recurse!
};
CPAnimationStep* currentStep = [self.consumableSteps lastObject];
// Note: do not animate to short steps
if (animated && currentStep.duration >= 0.02) {
[UIView animateWithDuration:currentStep.duration
delay:currentStep.delay
options:currentStep.options
animations:currentStep.step
completion:^(BOOL finished) {
if (finished) {
completionStep(TRUE);
} else {
completionStep(FALSE);
}
}];
} else {
void (^execution)(void) = ^{
currentStep.step();
completionStep(FALSE);
};
if (animated && currentStep.delay) {
[CPAnimationStep runBlock:execution afterDelay:currentStep.delay];
} else {
execution();
}
}
}
- (void) run {
[self runAnimated:YES];
}
#pragma mark - pretty-print
- (NSString*) description {
NSMutableString* result = [[NSMutableString alloc] initWithCapacity:100];
[result appendString:@"\n["];
if (self.delay > 0.0) {
[result appendFormat:@"after:%.1f ", self.delay];
}
if (self.duration > 0.0) {
[result appendFormat:@"for:%.1f ", self.duration];
}
if (self.options > 0) {
[result appendFormat:@"options:%d ", self.options];
}
[result appendFormat:@"animate:%@", self.step];
[result appendString:@"]"];
return result;
}
@end