LOTMaskContainer.m 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //
  2. // LOTMaskContainer.m
  3. // Lottie
  4. //
  5. // Created by brandon_withrow on 7/19/17.
  6. // Copyright © 2017 Airbnb. All rights reserved.
  7. //
  8. #import "LOTMaskContainer.h"
  9. #import "LOTPathInterpolator.h"
  10. #import "LOTNumberInterpolator.h"
  11. @interface LOTMaskNodeLayer : CAShapeLayer
  12. @property (nonatomic, readonly) LOTMask *maskNode;
  13. - (instancetype)initWithMask:(LOTMask *)maskNode;
  14. - (BOOL)hasUpdateForFrame:(NSNumber *)frame;
  15. @end
  16. @implementation LOTMaskNodeLayer {
  17. LOTPathInterpolator *_pathInterpolator;
  18. LOTNumberInterpolator *_opacityInterpolator;
  19. LOTNumberInterpolator *_expansionInterpolator;
  20. }
  21. - (instancetype)initWithMask:(LOTMask *)maskNode {
  22. self = [super init];
  23. if (self) {
  24. _pathInterpolator = [[LOTPathInterpolator alloc] initWithKeyframes:maskNode.maskPath.keyframes];
  25. _opacityInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:maskNode.opacity.keyframes];
  26. _expansionInterpolator = [[LOTNumberInterpolator alloc] initWithKeyframes:maskNode.expansion.keyframes];
  27. _maskNode = maskNode;
  28. self.fillColor = [UIColor blueColor].CGColor;
  29. }
  30. return self;
  31. }
  32. - (void)updateForFrame:(NSNumber *)frame withViewBounds:(CGRect)viewBounds {
  33. if ([self hasUpdateForFrame:frame]) {
  34. LOTBezierPath *path = [_pathInterpolator pathForFrame:frame cacheLengths:NO];
  35. if (self.maskNode.maskMode == LOTMaskModeSubtract) {
  36. CGMutablePathRef pathRef = CGPathCreateMutable();
  37. CGPathAddRect(pathRef, NULL, viewBounds);
  38. CGPathAddPath(pathRef, NULL, path.CGPath);
  39. self.path = pathRef;
  40. self.fillRule = @"even-odd";
  41. CGPathRelease(pathRef);
  42. } else {
  43. self.path = path.CGPath;
  44. }
  45. self.opacity = [_opacityInterpolator floatValueForFrame:frame];
  46. }
  47. }
  48. - (BOOL)hasUpdateForFrame:(NSNumber *)frame {
  49. return ([_pathInterpolator hasUpdateForFrame:frame] ||
  50. [_opacityInterpolator hasUpdateForFrame:frame]);
  51. }
  52. @end
  53. @implementation LOTMaskContainer {
  54. NSArray<LOTMaskNodeLayer *> *_masks;
  55. }
  56. - (instancetype)initWithMasks:(NSArray<LOTMask *> *)masks {
  57. self = [super init];
  58. if (self) {
  59. NSMutableArray *maskNodes = [NSMutableArray array];
  60. CALayer *containerLayer = [CALayer layer];
  61. for (LOTMask *mask in masks) {
  62. LOTMaskNodeLayer *node = [[LOTMaskNodeLayer alloc] initWithMask:mask];
  63. [maskNodes addObject:node];
  64. if (mask.maskMode == LOTMaskModeAdd ||
  65. mask == masks.firstObject) {
  66. [containerLayer addSublayer:node];
  67. } else {
  68. containerLayer.mask = node;
  69. CALayer *newContainer = [CALayer layer];
  70. [newContainer addSublayer:containerLayer];
  71. containerLayer = newContainer;
  72. }
  73. }
  74. [self addSublayer:containerLayer];
  75. _masks = maskNodes;
  76. }
  77. return self;
  78. }
  79. - (void)setCurrentFrame:(NSNumber *)currentFrame {
  80. if (_currentFrame == currentFrame) {
  81. return;
  82. }
  83. _currentFrame = currentFrame;
  84. for (LOTMaskNodeLayer *nodeLayer in _masks) {
  85. [nodeLayer updateForFrame:currentFrame withViewBounds:self.bounds];
  86. }
  87. }
  88. @end