Skip to content

Commit

Permalink
Add support for radial gradient
Browse files Browse the repository at this point in the history
  • Loading branch information
brandon_withrow committed Aug 4, 2017
1 parent a45b806 commit 0cfc576
Show file tree
Hide file tree
Showing 9 changed files with 1,051 additions and 910 deletions.
1,796 changes: 904 additions & 892 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions Lottie.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@
6274D0241F1E830E00E05049 /* LOTTransformInterpolator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6274D0201F1E830E00E05049 /* LOTTransformInterpolator.m */; };
6274D0251F1E830E00E05049 /* LOTTransformInterpolator.m in Sources */ = {isa = PBXBuildFile; fileRef = 6274D0201F1E830E00E05049 /* LOTTransformInterpolator.m */; };
6289053E1F33EA0F005154FA /* LOTCacheProvider.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = EE498E3D1F336A4900D1DFCD /* LOTCacheProvider.h */; };
628905411F352472005154FA /* LOTRadialGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6289053F1F352472005154FA /* LOTRadialGradientLayer.h */; };
628905421F352472005154FA /* LOTRadialGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6289053F1F352472005154FA /* LOTRadialGradientLayer.h */; };
628905431F352472005154FA /* LOTRadialGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 628905401F352472005154FA /* LOTRadialGradientLayer.m */; };
628905441F352472005154FA /* LOTRadialGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 628905401F352472005154FA /* LOTRadialGradientLayer.m */; };
628905451F352472005154FA /* LOTRadialGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 628905401F352472005154FA /* LOTRadialGradientLayer.m */; };
62BFC2DE1F14298D0068A342 /* LOTAnimatorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 62BFC2D01F14298D0068A342 /* LOTAnimatorNode.h */; };
62BFC2DF1F14298D0068A342 /* LOTAnimatorNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 62BFC2D01F14298D0068A342 /* LOTAnimatorNode.h */; };
62BFC2E01F14298D0068A342 /* LOTAnimatorNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 62BFC2D11F14298D0068A342 /* LOTAnimatorNode.m */; };
Expand Down Expand Up @@ -383,6 +388,8 @@
6274D0191F1E82D000E05049 /* LOTLayerContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LOTLayerContainer.m; sourceTree = "<group>"; };
6274D01F1F1E830E00E05049 /* LOTTransformInterpolator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LOTTransformInterpolator.h; path = "lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTTransformInterpolator.h"; sourceTree = SOURCE_ROOT; };
6274D0201F1E830E00E05049 /* LOTTransformInterpolator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LOTTransformInterpolator.m; path = "lottie-ios/Classes/RenderSystem/InterpolatorNodes/LOTTransformInterpolator.m"; sourceTree = SOURCE_ROOT; };
6289053F1F352472005154FA /* LOTRadialGradientLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LOTRadialGradientLayer.h; sourceTree = "<group>"; };
628905401F352472005154FA /* LOTRadialGradientLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LOTRadialGradientLayer.m; sourceTree = "<group>"; };
62BFC2D01F14298D0068A342 /* LOTAnimatorNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LOTAnimatorNode.h; path = "lottie-ios/Classes/RenderSystem/LOTAnimatorNode.h"; sourceTree = SOURCE_ROOT; };
62BFC2D11F14298D0068A342 /* LOTAnimatorNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LOTAnimatorNode.m; path = "lottie-ios/Classes/RenderSystem/LOTAnimatorNode.m"; sourceTree = SOURCE_ROOT; };
62BFC2D21F14298D0068A342 /* LOTFillRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LOTFillRenderer.h; path = "lottie-ios/Classes/RenderSystem/RenderNodes/LOTFillRenderer.h"; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -472,6 +479,8 @@
481A4A371E4A7885003CF62B /* Extensions */ = {
isa = PBXGroup;
children = (
6289053F1F352472005154FA /* LOTRadialGradientLayer.h */,
628905401F352472005154FA /* LOTRadialGradientLayer.m */,
48183C9A1E54E20B0039F121 /* CGGeometry+LOTAdditions.h */,
48183C9B1E54E20B0039F121 /* CGGeometry+LOTAdditions.m */,
481A4A3C1E4A7885003CF62B /* LOTHelpers.h */,
Expand Down Expand Up @@ -737,6 +746,7 @@
62BFC2DE1F14298D0068A342 /* LOTAnimatorNode.h in Headers */,
481A4AB11E4A7885003CF62B /* LOTShapeCircle.h in Headers */,
622F75E91F29508D00269858 /* LOTShapeGradientFill.h in Headers */,
628905411F352472005154FA /* LOTRadialGradientLayer.h in Headers */,
62BFC2E31F14298D0068A342 /* LOTFillRenderer.h in Headers */,
62BFC3031F1449380068A342 /* LOTBezierData.h in Headers */,
62BFC2ED1F14298D0068A342 /* LOTPathAnimator.h in Headers */,
Expand Down Expand Up @@ -775,6 +785,7 @@
62C9EA251F1EB49000DE7D07 /* LOTCompositionContainer.h in Headers */,
481A4AC21E4A7885003CF62B /* LOTShapeRectangle.h in Headers */,
62BFC2F31F14298D0068A342 /* LOTRenderGroup.h in Headers */,
628905421F352472005154FA /* LOTRadialGradientLayer.h in Headers */,
62C9EA441F1FDBF000DE7D07 /* LOTCircleAnimator.h in Headers */,
62BFC3041F1449380068A342 /* LOTBezierData.h in Headers */,
6201FAE71F200B4A00A047C9 /* LOTMaskContainer.h in Headers */,
Expand Down Expand Up @@ -981,6 +992,7 @@
6274D00F1F1D6CE200E05049 /* LOTStrokeRenderer.m in Sources */,
6274CFA21F17E94C00E05049 /* LOTPathInterpolator.m in Sources */,
6274D0231F1E830E00E05049 /* LOTTransformInterpolator.m in Sources */,
628905431F352472005154FA /* LOTRadialGradientLayer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1038,6 +1050,7 @@
6274D0111F1D6CE200E05049 /* LOTStrokeRenderer.m in Sources */,
6274CFA41F17E94C00E05049 /* LOTPathInterpolator.m in Sources */,
6274D0251F1E830E00E05049 /* LOTTransformInterpolator.m in Sources */,
628905451F352472005154FA /* LOTRadialGradientLayer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1075,6 +1088,7 @@
6274CEBC1F157DCD00E05049 /* LOTNumberInterpolator.m in Sources */,
481A4AA21E4A7885003CF62B /* UIColor+Expanded.m in Sources */,
622F766E1F2BCE1300269858 /* LOTRepeaterRenderer.m in Sources */,
628905441F352472005154FA /* LOTRadialGradientLayer.m in Sources */,
622F75EC1F29508D00269858 /* LOTShapeGradientFill.m in Sources */,
6201FAE91F200B4A00A047C9 /* LOTMaskContainer.m in Sources */,
62BFC2E61F14298D0068A342 /* LOTFillRenderer.m in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion lottie-ios/Classes/Extensions/LOTHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#import "LOTBezierPath.h"

#define ENABLE_DEBUG_LOGGING NO
#define ENABLE_DEBUG_SHAPES NO
#define ENABLE_DEBUG_SHAPES YES

#endif /* LOTHelpers_h */

Expand Down
20 changes: 20 additions & 0 deletions lottie-ios/Classes/Extensions/LOTRadialGradientLayer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// LOTAnimationView
// LottieAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import <Foundation/Foundation.h>

@interface LOTRadialGradientLayer : CALayer

@property CGPoint startPoint;
@property CGPoint endPoint;

@property (nonatomic, copy) NSArray *colors;
@property (nonatomic, copy) NSArray<NSNumber *> *locations;
@property (nonatomic, assign) BOOL isRadial;

@end
82 changes: 82 additions & 0 deletions lottie-ios/Classes/Extensions/LOTRadialGradientLayer.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// LOTAnimationView
// LottieAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//

#import "LOTRadialGradientLayer.h"
#import "CGGeometry+LOTAdditions.h"

@implementation LOTRadialGradientLayer

@dynamic isRadial;
@dynamic startPoint;
@dynamic endPoint;
@dynamic colors;
@dynamic locations;

+ (BOOL)needsDisplayForKey:(NSString *)key {
if ([key isEqualToString:@"startPoint"] ||
[key isEqualToString:@"endPoint"] ||
[key isEqualToString:@"colors"] ||
[key isEqualToString:@"locations"] ||
[key isEqualToString:@"isRadial"]) {
return YES;
}
return [super needsDisplayForKey:key];
}

- (id)actionForKey:(NSString *)key {
if ([key isEqualToString:@"startPoint"] ||
[key isEqualToString:@"endPoint"] ||
[key isEqualToString:@"colors"] ||
[key isEqualToString:@"locations"] ||
[key isEqualToString:@"isRadial"]) {
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:key];
theAnimation.fromValue = [self.presentationLayer valueForKey:key];
return theAnimation;
}
return [super actionForKey:key];
}

- (void)drawInContext:(CGContextRef)ctx {
NSInteger numberOfLocations = self.locations.count;
NSInteger numbOfComponents = 0;
CGColorSpaceRef colorSpace = NULL;

if (self.colors.count) {
CGColorRef colorRef = (__bridge CGColorRef)[self.colors objectAtIndex:0];
numbOfComponents = CGColorGetNumberOfComponents(colorRef);
colorSpace = CGColorGetColorSpace(colorRef);
}

CGPoint origin = self.startPoint;
CGFloat radius = LOT_PointDistanceFromPoint(self.startPoint, self.endPoint);

CGFloat gradientLocations[numberOfLocations];
CGFloat gradientComponents[numberOfLocations * numbOfComponents];

for (NSInteger locationIndex = 0; locationIndex < numberOfLocations; locationIndex++) {

gradientLocations[locationIndex] = [self.locations[locationIndex] floatValue];
const CGFloat *colorComponents = CGColorGetComponents((__bridge CGColorRef)self.colors[locationIndex]);

for (NSInteger componentIndex = 0; componentIndex < numbOfComponents; componentIndex++) {
gradientComponents[numbOfComponents * locationIndex + componentIndex] = colorComponents[componentIndex];
}
}

CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientComponents, gradientLocations, numberOfLocations);

if (self.isRadial) {
CGContextDrawRadialGradient(ctx, gradient, origin, 0, origin, radius, kCGGradientDrawsAfterEndLocation);
} else {
CGContextDrawLinearGradient(ctx, gradient, self.startPoint, self.endPoint, kCGGradientDrawsAfterEndLocation);
}

CGGradientRelease(gradient);
}

@end
6 changes: 6 additions & 0 deletions lottie-ios/Classes/Models/LOTShapeGradientFill.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

NS_ASSUME_NONNULL_BEGIN

typedef enum : NSUInteger {
LOTGradientTypeLinear,
LOTGradientTypeRadial
} LOTGradientType;

@interface LOTShapeGradientFill : NSObject

- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary;
Expand All @@ -22,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) LOTKeyframeGroup *gradient;
@property (nonatomic, readonly) LOTKeyframeGroup *opacity;
@property (nonatomic, readonly) BOOL evenOddFillRule;
@property (nonatomic, readonly) LOTGradientType type;

@end

Expand Down
5 changes: 4 additions & 1 deletion lottie-ios/Classes/Models/LOTShapeGradientFill.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ - (void)_mapFromJSON:(NSDictionary *)jsonDictionary {
}

NSNumber *type = jsonDictionary[@"t"];

if (type.integerValue != 1) {
NSLog(@"%s: Warning: Only Linear Gradients are supported.", __PRETTY_FUNCTION__);
_type = LOTGradientTypeRadial;
} else {
_type = LOTGradientTypeLinear;
}

NSDictionary *start = jsonDictionary[@"s"];
Expand Down
2 changes: 1 addition & 1 deletion lottie-ios/Classes/Private/LOTAnimationView.m
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ - (void)playFromFrame:(nonnull NSNumber *)fromStartFrame
return;
}
if (_animationProgress == 1) {
self.animationProgress = 0;
_animationProgress = 0;
}
NSTimeInterval offset = MAX(0, (_animationProgress * (_sceneModel.endFrame.floatValue - _sceneModel.startFrame.floatValue)) - fromStartFrame.floatValue) / _sceneModel.framerate.floatValue;
NSTimeInterval duration = ((toEndFrame.floatValue - fromStartFrame.floatValue) / _sceneModel.framerate.floatValue);
Expand Down
34 changes: 19 additions & 15 deletions lottie-ios/Classes/RenderSystem/RenderNodes/LOTGradientFillRender.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
#import "LOTNumberInterpolator.h"
#import "CGGeometry+LOTAdditions.h"
#import "LOTHelpers.h"
#import "LOTRadialGradientLayer.h"

@implementation LOTGradientFillRender {
BOOL _evenOddFillRule;
CALayer *centerPoint_DEBUG;

CAShapeLayer *_maskShape;
CAGradientLayer *_gradientOpacityLayer;
CAGradientLayer *_gradientLayer;
LOTRadialGradientLayer *_gradientOpacityLayer;
LOTRadialGradientLayer *_gradientLayer;
NSInteger _numberOfPositions;

CGPoint _startPoint;
Expand Down Expand Up @@ -48,7 +49,8 @@ - (instancetype _Nonnull )initWithInputNode:(LOTAnimatorNode *_Nonnull)inputNode
_maskShape.fillColor = [UIColor whiteColor].CGColor;
_maskShape.actions = @{@"path": [NSNull null]};

_gradientOpacityLayer = [CAGradientLayer new];
_gradientOpacityLayer = [LOTRadialGradientLayer new];
_gradientOpacityLayer.isRadial = (fill.type == LOTGradientTypeRadial);
_gradientOpacityLayer.actions = @{@"startPoint" : [NSNull null],
@"endPoint" : [NSNull null],
@"opacity" : [NSNull null],
Expand All @@ -59,7 +61,8 @@ - (instancetype _Nonnull )initWithInputNode:(LOTAnimatorNode *_Nonnull)inputNode
_gradientOpacityLayer.mask = _maskShape;
[wrapperLayer addSublayer:_gradientOpacityLayer];

_gradientLayer = [CAGradientLayer new];
_gradientLayer = [LOTRadialGradientLayer new];
_gradientLayer.isRadial = (fill.type == LOTGradientTypeRadial);
_gradientLayer.mask = wrapperLayer;
_gradientLayer.actions = [_gradientOpacityLayer.actions copy];
[self.outputLayer addSublayer:_gradientLayer];
Expand Down Expand Up @@ -116,8 +119,16 @@ - (void)performLocalUpdate {
UIColor *opacityColor = [UIColor colorWithWhite:1 alpha:opacity.floatValue];
[opacityArray addObject:(id)(opacityColor.CGColor)];
}
_gradientOpacityLayer.locations = opacitylocationsArray;
_gradientOpacityLayer.colors = opacityArray;
if (opacityArray.count == 0) {
_gradientOpacityLayer.backgroundColor = [UIColor whiteColor].CGColor;
} else {
_gradientOpacityLayer.startPoint = _startPoint;
_gradientOpacityLayer.endPoint = _endPoint;
_gradientOpacityLayer.locations = opacitylocationsArray;
_gradientOpacityLayer.colors = opacityArray;
}
_gradientLayer.startPoint = _startPoint;
_gradientLayer.endPoint = _endPoint;
_gradientLayer.locations = locationsArray;
_gradientLayer.colors = colorArray;
}
Expand All @@ -126,19 +137,12 @@ - (void)rebuildOutputs {
CGRect frame = [self.inputNode.outputPath bounds];
CGPoint modifiedAnchor = CGPointMake(-frame.origin.x / frame.size.width,
-frame.origin.y / frame.size.height);
CGPoint modifiedStart = CGPointMake((_startPoint.x - frame.origin.x) / frame.size.width,
(_startPoint.y - frame.origin.y) / frame.size.height);
CGPoint modifiedEnd = CGPointMake((_endPoint.x - frame.origin.x) / frame.size.width,
(_endPoint.y - frame.origin.y) / frame.size.height);
_maskShape.path = self.inputNode.outputPath.CGPath;
_gradientOpacityLayer.bounds = frame;
_gradientOpacityLayer.anchorPoint = modifiedAnchor;
_gradientOpacityLayer.startPoint = modifiedStart;
_gradientOpacityLayer.endPoint = modifiedEnd;

_gradientLayer.bounds = frame;
_gradientLayer.anchorPoint = modifiedAnchor;
_gradientLayer.startPoint = modifiedStart;
_gradientLayer.endPoint = modifiedEnd;

}

- (NSDictionary *)actionsForRenderLayer {
Expand Down

0 comments on commit 0cfc576

Please sign in to comment.