Skip to content
This repository has been archived by the owner on Mar 3, 2020. It is now read-only.

Animation groups #275

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Podfile.lock
Expand Up @@ -7,4 +7,4 @@ DEPENDENCIES:
SPEC CHECKSUMS:
OCMock: a6a7dc0e3997fb9f35d99f72528698ebf60d64f2

COCOAPODS: 0.37.1
COCOAPODS: 0.38.2
35 changes: 35 additions & 0 deletions pop-tests/POPAnimationTests.mm
Expand Up @@ -23,6 +23,7 @@
#import "POPBaseAnimationTests.h"
#import "POPCGUtils.h"
#import "POPAnimationInternal.h"
#import "POPGroupAnimation.h"

using namespace POP;

Expand Down Expand Up @@ -888,4 +889,38 @@ - (void)testNSCopyingSupportPOPBasicAnimation
XCTAssertEqualObjects(copy.timingFunction, anim.timingFunction, @"expected equality; value1:%@ value2:%@", copy.timingFunction, anim.timingFunction);
}

- (void)testGroupAnimation
{
CALayer* layer = [CALayer layer];

__block NSInteger testValue = 0;

POPGroupAnimation* group = [POPGroupAnimation animation];
group.animationDidStartBlock = ^(POPAnimation* anim) {
XCTAssertEqual(testValue, 0, @"expected 0 but got %ld", (long)testValue);
testValue++;
};

POPBasicAnimation* test = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerBorderWidth];
test.toValue = @(5);
test.animationDidStartBlock = ^(POPAnimation* anim) {
XCTAssertEqual(testValue, 1, @"expected 1 but got %ld", (long)testValue);
testValue++;
};
test.completionBlock = ^(POPAnimation* anim, BOOL finished) {
XCTAssertEqual(testValue, 2, @"expected 2 but got %ld", (long)testValue);
testValue++;
};

group.animations = @[ test ];

group.completionBlock = ^(POPAnimation* anim, BOOL finished) {
XCTAssertEqual(testValue, 3, @"expected 3 but got %ld", (long)testValue);
testValue++;
};
[layer pop_addAnimation:group forKey:@"group"];

POPAnimatorRenderDuration(self.animator, self.beginTime, 5, 0.01);
}

@end
16 changes: 16 additions & 0 deletions pop.xcodeproj/project.pbxproj
Expand Up @@ -192,6 +192,12 @@
ECDA0CD118C92D3900D14897 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECC5A89D162FBD9B00F7F15C /* CoreGraphics.framework */; };
ECF01ED518C92B7F009E0AD1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EC19121B162FB53A00E0CC76 /* Foundation.framework */; };
ECF01ED618C92B7F009E0AD1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ECEED93D18C91ACF00DD95F2 /* UIKit.framework */; };
FAAEA3EF1BAB6C09005069B1 /* POPGroupAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAEA3ED1BAB6C09005069B1 /* POPGroupAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; };
FAAEA3F01BAB6C09005069B1 /* POPGroupAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAEA3ED1BAB6C09005069B1 /* POPGroupAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; };
FAAEA3F11BAB6C09005069B1 /* POPGroupAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAEA3ED1BAB6C09005069B1 /* POPGroupAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; };
FAAEA3F21BAB6C09005069B1 /* POPGroupAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAAEA3EE1BAB6C09005069B1 /* POPGroupAnimation.mm */; settings = {ASSET_TAGS = (); }; };
FAAEA3F31BAB6C09005069B1 /* POPGroupAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAAEA3EE1BAB6C09005069B1 /* POPGroupAnimation.mm */; settings = {ASSET_TAGS = (); }; };
FAAEA3F41BAB6C09005069B1 /* POPGroupAnimation.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAAEA3EE1BAB6C09005069B1 /* POPGroupAnimation.mm */; settings = {ASSET_TAGS = (); }; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -330,6 +336,8 @@
ECD80F1018CFD2EF00AE4303 /* POPGeometry.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = POPGeometry.mm; sourceTree = "<group>"; };
ECEED93D18C91ACF00DD95F2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
ECF01ED318C92B7F009E0AD1 /* pop-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "pop-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
FAAEA3ED1BAB6C09005069B1 /* POPGroupAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = POPGroupAnimation.h; sourceTree = "<group>"; };
FAAEA3EE1BAB6C09005069B1 /* POPGroupAnimation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = POPGroupAnimation.mm; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -544,6 +552,8 @@
EC8F015318FFBD5600DF8905 /* POPBasicAnimationInternal.h */,
5E17BB1E17457345009842B6 /* POPCustomAnimation.h */,
5E17BB1F17457345009842B6 /* POPCustomAnimation.mm */,
FAAEA3ED1BAB6C09005069B1 /* POPGroupAnimation.h */,
FAAEA3EE1BAB6C09005069B1 /* POPGroupAnimation.mm */,
EC8F015A18FFBE8C00DF8905 /* POPDecayAnimation.h */,
EC8F015B18FFBE8C00DF8905 /* POPDecayAnimation.mm */,
EC8F016018FFBE9D00DF8905 /* POPDecayAnimationInternal.h */,
Expand Down Expand Up @@ -685,6 +695,7 @@
0B6BE76A19FFD41100762101 /* POPAnimationEvent.h in Headers */,
0B6BE76919FFD40700762101 /* POP.h in Headers */,
0B6BE76819FFD3FF00762101 /* POPAnimationTracer.h in Headers */,
FAAEA3F01BAB6C09005069B1 /* POPGroupAnimation.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -697,6 +708,7 @@
EC191295162FB5EC00E0CC76 /* POPAnimation.h in Headers */,
EC191297162FB5EC00E0CC76 /* POPAnimator.h in Headers */,
EC35DB2D18EE3E820023E077 /* POPAnimationTracerInternal.h in Headers */,
FAAEA3EF1BAB6C09005069B1 /* POPGroupAnimation.h in Headers */,
EC191299162FB5EC00E0CC76 /* POPAnimatableProperty.h in Headers */,
EC8F014F18FFBD3E00DF8905 /* POPBasicAnimation.h in Headers */,
EC8F014018FFBBD300DF8905 /* POPPropertyAnimation.h in Headers */,
Expand Down Expand Up @@ -737,6 +749,7 @@
EC6885D118C7BD8500C6194C /* TransformationMatrix.h in Headers */,
EC6885B718C7BD2600C6194C /* POPAnimationEventInternal.h in Headers */,
EC35DB2E18EE3E820023E077 /* POPAnimationTracerInternal.h in Headers */,
FAAEA3F11BAB6C09005069B1 /* POPGroupAnimation.h in Headers */,
EC6885C818C7BD5F00C6194C /* POPLayerExtras.h in Headers */,
EC8F015018FFBD3E00DF8905 /* POPBasicAnimation.h in Headers */,
EC8F014118FFBBD300DF8905 /* POPPropertyAnimation.h in Headers */,
Expand Down Expand Up @@ -1021,6 +1034,7 @@
0B6BE7DC19FFD92700762101 /* POPAnimator.mm in Sources */,
0B6BE7DD19FFD92700762101 /* POPCGUtils.mm in Sources */,
0B6BE7DE19FFD92700762101 /* POPGeometry.mm in Sources */,
FAAEA3F31BAB6C09005069B1 /* POPGroupAnimation.mm in Sources */,
0B6BE7DF19FFD92700762101 /* POPLayerExtras.mm in Sources */,
0B6BE7E019FFD92800762101 /* POPMath.mm in Sources */,
0B6BE7E119FFD92800762101 /* POPVector.mm in Sources */,
Expand All @@ -1046,6 +1060,7 @@
EC35DB2B18EE3E820023E077 /* POPAnimationTracer.mm in Sources */,
5E17BB2117457345009842B6 /* POPCustomAnimation.mm in Sources */,
EC67007418D3D89F00F7387F /* POPCGUtils.mm in Sources */,
FAAEA3F21BAB6C09005069B1 /* POPGroupAnimation.mm in Sources */,
ECD80F1318CFD2EF00AE4303 /* POPGeometry.mm in Sources */,
EC8F015E18FFBE8C00DF8905 /* POPDecayAnimation.mm in Sources */,
EC9997561756A0C300A73F49 /* POPAnimationEvent.mm in Sources */,
Expand All @@ -1071,6 +1086,7 @@
EC35DB2C18EE3E820023E077 /* POPAnimationTracer.mm in Sources */,
EC67007518D3D89F00F7387F /* POPCGUtils.mm in Sources */,
ECD80F1418CFD2EF00AE4303 /* POPGeometry.mm in Sources */,
FAAEA3F41BAB6C09005069B1 /* POPGroupAnimation.mm in Sources */,
EC6885C918C7BD6300C6194C /* POPLayerExtras.mm in Sources */,
EC8F015F18FFBE8C00DF8905 /* POPDecayAnimation.mm in Sources */,
EC6885B918C7BD3000C6194C /* POPAnimationExtras.mm in Sources */,
Expand Down
1 change: 1 addition & 0 deletions pop/POP.h
Expand Up @@ -25,5 +25,6 @@
#import <pop/POPLayerExtras.h>
#import <pop/POPPropertyAnimation.h>
#import <pop/POPSpringAnimation.h>
#import <pop/POPGroupAnimation.h>

#endif /* POP_POP_H */
20 changes: 17 additions & 3 deletions pop/POPAnimationInternal.h
Expand Up @@ -27,6 +27,7 @@ enum POPAnimationType
kPOPAnimationDecay,
kPOPAnimationBasic,
kPOPAnimationCustom,
kPOPAnimationGroup,
};

typedef struct
Expand Down Expand Up @@ -229,7 +230,8 @@ struct _POPAnimationState
bool autoreverses:1;
bool repeatForever:1;
bool customFinished:1;

bool groupFinished:1;

_POPAnimationState(id __unsafe_unretained anim) :
self(anim),
type((POPAnimationType)0),
Expand Down Expand Up @@ -261,7 +263,8 @@ struct _POPAnimationState
userSpecifiedDynamics(false),
autoreverses(false),
repeatForever(false),
customFinished(false) {}
customFinished(false),
groupFinished(false) {}

virtual ~_POPAnimationState()
{
Expand All @@ -278,6 +281,10 @@ struct _POPAnimationState
return kPOPAnimationCustom == type;
}

bool isGroup() {
return kPOPAnimationGroup == type;
}

bool isStarted() {
return 0 != startTime;
}
Expand Down Expand Up @@ -413,7 +420,9 @@ struct _POPAnimationState
if (isCustom()) {
return customFinished;
}

if ( isGroup() ) {
return groupFinished;
}
return false;
}

Expand All @@ -439,6 +448,11 @@ struct _POPAnimationState
advanced = true;
break;
}
case kPOPAnimationGroup: {
groupFinished = [self _advance:obj currentTime:time elapsedTime:dt] ? false : true;
advanced = true;
break;
}
default:
break;
}
Expand Down
14 changes: 14 additions & 0 deletions pop/POPAnimator.mm
Expand Up @@ -712,6 +712,20 @@ - (NSArray *)animationKeysForObject:(id)obj
return keys;
}

- (NSArray*)animationsForObject:(id)obj
{
// lock
OSSpinLockLock(&_lock);

// lookup animation
NSDictionary *keyAnimationsDict = (__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj);
NSArray* animations = keyAnimationsDict.allValues;

// unlock
OSSpinLockUnlock(&_lock);
return animations;
}

- (id)animationForObject:(id)obj key:(NSString *)key
{
// lock
Expand Down
1 change: 1 addition & 0 deletions pop/POPAnimatorPrivate.h
Expand Up @@ -54,6 +54,7 @@
- (void)removeAnimationForObject:(id)obj key:(NSString *)key;
- (NSArray *)animationKeysForObject:(id)obj;
- (POPAnimation *)animationForObject:(id)obj key:(NSString *)key;
- (NSArray*)animationsForObject:(id)obj;

/**
@abstract Add an animator observer. Observer will be notified of each subsequent animator advance until removal.
Expand Down
28 changes: 28 additions & 0 deletions pop/POPGroupAnimation.h
@@ -0,0 +1,28 @@
//
// POPGroupAnimation.h
// pop
//
// Created by Alexander Cohen on 2015-09-17.
// Copyright © 2015 Facebook. All rights reserved.
//

#import <pop/POPAnimation.h>

/**
@abstract POPGroupAnimation is a concrete animation subclass for grouped animations.
*/
@interface POPGroupAnimation : POPAnimation

/**
@abstract Creates and returns an initialized group animation instance.
@discussion This is the designated initializer.
@return The initialized group animation instance.
*/
+ (instancetype)animation;

/**
@abstract The array of POPAnimtions to run in this group.
*/
@property (nonatomic,copy) NSArray* animations;

@end
116 changes: 116 additions & 0 deletions pop/POPGroupAnimation.mm
@@ -0,0 +1,116 @@
//
// POPGroupAnimation.m
// pop
//
// Created by Alexander Cohen on 2015-09-17.
// Copyright © 2015 Facebook. All rights reserved.
//

#import "POPGroupAnimation.h"
#import "POPAnimationInternal.h"
#import "POPAnimatorPrivate.h"

@implementation POPGroupAnimation {
NSArray* _animations;
NSArray* _animationKeys;
BOOL _addedAnimations;
}

+ (instancetype)animation
{
return [[[self class] alloc] _init];
}

- (void)setAnimations:(NSArray *)animations
{
NSAssert( _addedAnimations == NO, @"cannot change the animations in an ongoing group animation");
_animations = [animations copy];
}

- (NSArray*)animations
{
return [_animations copy];
}

- (id)_init
{
self = [super _init];
if (nil != self) {
_state->type = kPOPAnimationGroup;
}
return self;
}

- (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime
{
// add all the animations if needed
if ( !_addedAnimations )
{
_addedAnimations = YES;

NSMutableArray* keys = [NSMutableArray array];
for ( POPAnimation* anim in self.animations )
{
NSString* key = [[NSUUID UUID] UUIDString];
[keys addObject:key];
[object pop_addAnimation:anim forKey:key];
}
_animationKeys = [keys copy];
}

// check for animation doneness
NSUInteger animsLeft = 0;
for ( NSString* key in _animationKeys )
{
POPAnimation* anim = [object pop_animationForKey:key];
if ( anim )
animsLeft++;
}

return animsLeft > 0;
}

- (void)setPaused:(BOOL)paused
{
[super setPaused:paused];
for ( POPAnimation* anim in _animations )
anim.paused = paused;
}

- (void)setAutoreverses:(BOOL)autoreverses
{
[super setAutoreverses:autoreverses];
for ( POPAnimation* anim in _animations )
anim.autoreverses = autoreverses;
}

- (void)setRepeatCount:(NSInteger)repeatCount
{
[super setRepeatCount:repeatCount];
for ( POPAnimation* anim in _animations )
anim.repeatCount = repeatCount;
}

- (void)setRepeatForever:(BOOL)repeatForever
{
[super setRepeatForever:repeatForever];
for ( POPAnimation* anim in _animations )
anim.repeatForever = repeatForever;
}

@end

@implementation POPGroupAnimation (NSCopying)

- (instancetype)copyWithZone:(NSZone *)zone {

POPGroupAnimation *copy = [super copyWithZone:zone];

if (copy) {
copy.animations = self.animations;
}

return copy;
}

@end