两个动画效果来了解一下CALayer的两个重要的subClass:CAGradientLayer和CAShapeLayer。先看CAShapeLayer,我们做一个和Spark相机一样的圆形进度,每一段有一种颜色,标识不同时间段录的视频。
- CGPoint arcCenter = CGPointMake(CGRectGetMidY(self.bounds), CGRectGetMidX(self.bounds));
- CGFloat radius = CGRectGetMidX(self.bounds) - insets.top - insets.bottom;
- self.circlePath = [UIBezierPath bezierPathWithArcCenter:arcCenter
- radius:radius
- startAngle:M_PI
- endAngle:-M_PI
- clockwise:NO];
- CAShapeLayer *backgroundLayer = [CAShapeLayerlayer];
- backgroundLayer.path = self.circlePath.CGPath;
- backgroundLayer.strokeColor = [[UIColor lightGrayColor] CGColor];
- backgroundLayer.fillColor = [[UIColorclearColor] CGColor];
- backgroundLayer.lineWidth = self.strokeWidth;
- [self.layer addSublayer:backgroundLayer];
- CAShapeLayer *progressLayer = [CAShapeLayerlayer];
- progressLayer.path = self.circlePath.CGPath;
- progressLayer.strokeColor = [[selfrandomColor] CGColor];
- progressLayer.fillColor = [[UIColorclearColor] CGColor];
- progressLayer.lineWidth = self.strokeWidth;
- progressLayer.strokeEnd = 0.f;
- [self.progressLayers addObject:progressLayer];
- self.currentProgressLayer = progressLayer;
- - (void)addNewLayer
- {
- CAShapeLayer *progressLayer = [CAShapeLayer layer];
- progressLayer.path = self.circlePath.CGPath;
- progressLayer.strokeColor = [[self randomColor] CGColor];
- progressLayer.fillColor = [[UIColor clearColor] CGColor];
- progressLayer.lineWidth = self.strokeWidth;
- progressLayer.strokeEnd = 0.f;
- [self.layer addSublayer:progressLayer];
- [self.progressLayers addObject:progressLayer];
- self.currentProgressLayer = progressLayer;
- }
- - (void)updateAnimations
- {
- CGFloat duration = self.duration * (1.f - [[self.progressLayers firstObject] strokeEnd]);
- CGFloat strokeEndFinal = 1.f;
- for (CAShapeLayer *progressLayer in self.progressLayers)
- {
- CABasicAnimation *strokeEndAnimation = nil;
- strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
- strokeEndAnimation.duration = duration;
- strokeEndAnimation.fromValue = @(progressLayer.strokeEnd);
- strokeEndAnimation.toValue = @(strokeEndFinal);
- strokeEndAnimation.autoreverses = NO;
- strokeEndAnimation.repeatCount = 0.f;
- strokeEndAnimation.fillMode = kCAFillModeForwards;
- strokeEndAnimation.removedOnCompletion = NO;
- strokeEndAnimation.delegate = self;
- [progressLayer addAnimation:strokeEndAnimation forKey:@"strokeEndAnimation"];
- strokeEndFinal -= (progressLayer.strokeEnd - progressLayer.strokeStart);
- if (progressLayer != self.currentProgressLayer)
- {
- CABasicAnimation *strokeStartAnimation = nil;
- strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
- strokeStartAnimation.duration = duration;
- strokeStartAnimation.fromValue = @(progressLayer.strokeStart);
- strokeStartAnimation.toValue = @(strokeEndFinal);
- strokeStartAnimation.autoreverses = NO;
- strokeStartAnimation.repeatCount = 0.f;
- strokeStartAnimation.fillMode = kCAFillModeForwards;
- strokeStartAnimation.removedOnCompletion = NO;
- [progressLayer addAnimation:strokeStartAnimation forKey:@"strokeStartAnimation"];
- }
- }
- CABasicAnimation *backgroundLayerAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
- backgroundLayerAnimation.duration = duration;
- backgroundLayerAnimation.fromValue = @(self.backgroundLayer.strokeStart);
- backgroundLayerAnimation.toValue = @(1.f);
- backgroundLayerAnimation.autoreverses = NO;
- backgroundLayerAnimation.repeatCount = 0.f;
- backgroundLayerAnimation.fillMode = kCAFillModeForwards;
- backgroundLayerAnimation.removedOnCompletion = NO;
- backgroundLayerAnimation.delegate = self;
- [self.backgroundLayer addAnimation:backgroundLayerAnimation forKey:@"strokeStartAnimation"];
- }
- - (void)removeAnimations
- {
- for (CAShapeLayer *progressLayer in self.progressLayers)
- {
- progressLayer.strokeStart = [progressLayer.presentationLayer strokeStart];
- progressLayer.strokeEnd = [progressLayer.presentationLayer strokeEnd];
- [progressLayer removeAllAnimations];
- }
- self.backgroundLayer.strokeStart = [self.backgroundLayer.presentationLayer strokeStart];
- [self.backgroundLayer removeAllAnimations];
- }
- - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
- {
- if (self.hasFinishedAnimating == NO && flag)
- {
- [self removeAnimations];
- self.finishedAnimating = flag;
- }
- }
- + (Class)layerClass {
- return [CAGradientLayer class];
- }
- // Use a horizontal gradient
- CAGradientLayer *layer = (id)[self layer];
- [layer setStartPoint:CGPointMake(0.0, 0.5)];
- [layer setEndPoint:CGPointMake(1.0, 0.5)];
- // Create colors using hues in +5 increments
- NSMutableArray *colors = [NSMutableArray array];
- for (NSInteger hue = 0; hue <= 360; hue += 5) {
- UIColor *color;
- color = [UIColor colorWithHue:1.0 * hue / 360.0
- saturation:1.0
- brightness:1.0
- alpha:1.0];
- [colors addObject:(id)[color CGColor]];
- }
- [layer setColors:[NSArray arrayWithArray:colors]];
- - (void)performAnimation {
- // Move the last color in the array to the front
- // shifting all the other colors.
- CAGradientLayer *layer = (id)[self layer];
- NSMutableArray *mutable = [[layer colors] mutableCopy];
- id lastColor = [[mutable lastObject] retain];
- [mutable removeLastObject];
- [mutable insertObject:lastColor atIndex:0];
- [lastColor release];
- NSArray *shiftedColors = [NSArray arrayWithArray:mutable];
- [mutable release];
- // Update the colors on the model layer
- [layer setColors:shiftedColors];
- // Create an animation to slowly move the gradient left to right.
- CABasicAnimation *animation;
- animation = [CABasicAnimation animationWithKeyPath:@"colors"];
- [animation setToValue:shiftedColors];
- [animation setDuration:0.08];
- [animation setRemovedOnCompletion:YES];
- [animation setFillMode:kCAFillModeForwards];
- [animation setDelegate:self];
- [layer addAnimation:animation forKey:@"animateGradient"];
- }
- - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
- [self performAnimation];
- }
- @property (nonatomic, readonly) CALayer *maskLayer;
- @property (nonatomic, assign) CGFloat progress;
- maskLayer = [CALayer layer];
- [maskLayer setFrame:CGRectMake(0, 0, 0, frame.size.height)];
- [maskLayer setBackgroundColor:[[UIColor blackColor] CGColor]];
- [layer setMask:maskLayer];
- - (void)setProgress:(CGFloat)value {
- if (progress != value) {
- // Progress values go from 0.0 to 1.0
- progress = MIN(1.0, fabs(value));
- [self setNeedsLayout];
- }
- }
- - (void)layoutSubviews {
- // Resize our mask layer based on the current progress
- CGRect maskRect = [maskLayer frame];
- maskRect.size.width = CGRectGetWidth([self bounds]) * progress;
- [maskLayer setFrame:maskRect];
- }