123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- //
- // RMDownloadIndicator.m
- // BezierLoaders
- //
- // Created by Mahesh on 1/30/14.
- // Copyright (c) 2014 Mahesh. All rights reserved.
- //
- #import "RMDownloadIndicator.h"
- #import "RMDisplayLabel.h"
- @interface RMDownloadIndicator()
- // this contains list of paths to be animated through
- @property(nonatomic, strong)NSMutableArray *paths;
- // the shaper layers used for display
- @property(nonatomic, strong)CAShapeLayer *indicateShapeLayer;
- @property(nonatomic, strong)CAShapeLayer *coverLayer;
- // this is the layer used for animation
- @property(nonatomic, strong)CAShapeLayer *animatingLayer;
- // the type of indicator
- @property(nonatomic, assign)RMIndicatorType type;
- // this applies to the covering stroke (default: 2)
- @property(nonatomic, assign)CGFloat coverWidth;
- // the last updatedPath
- @property(nonatomic, strong)UIBezierPath *lastUpdatedPath;
- @property(nonatomic, assign)CGFloat lastSourceAngle;
- // this the animation duration (default: 0.5)
- @property(nonatomic, assign)CGFloat animationDuration;
- // this is display label that displays % downloaded
- @property(nonatomic, strong)RMDisplayLabel *displayLabel;
- @end
- @implementation RMDownloadIndicator
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- // Initialization code
- _type = kRMFilledIndicator;
- [self initAttributes];
- }
- return self;
- }
- - (id)initWithFrame:(CGRect)frame type:(RMIndicatorType)type
- {
- self = [super initWithFrame:frame];
- if (self) {
- // Initialization code
- _type = type;
- [self initAttributes];
- }
- return self;
- }
- /*
- // Only override drawRect: if you perform custom drawing.
- // An empty implementation adversely affects performance during animation.
- - (void)drawRect:(CGRect)rect
- {
- // Drawing code
- }
- */
- - (void)initAttributes
- {
- // 首先设置半径的属性
- if(_type == kRMClosedIndicator)
- {
- self.radiusPercent = 0.5;
- _coverLayer = [CAShapeLayer layer];
- _animatingLayer = _coverLayer;
-
- // 设置填充颜色
- _fillColor = [UIColor clearColor];
- _strokeColor = [UIColor whiteColor];
- _closedIndicatorBackgroundStrokeColor = [UIColor colorWithRed:27./255 green:153./255 blue:225./255 alpha:1.0f];
- _coverWidth = 5.0;
-
- //[self addDisplayLabel];
- }
- else
- {
- if(_type == kRMFilledIndicator)
- {
- // only indicateShapeLayer
- _indicateShapeLayer = [CAShapeLayer layer];
- _animatingLayer = _indicateShapeLayer;
- self.radiusPercent = 0.5;
- _coverWidth = 2.0;
- }
- else
- {
- // indicateShapeLayer and coverLayer
- _indicateShapeLayer = [CAShapeLayer layer];
- _coverLayer = [CAShapeLayer layer];
- _animatingLayer = _indicateShapeLayer;
- _coverWidth = 2.0;
- self.radiusPercent = 0.4;
- }
- // set the fill color
- _fillColor = [UIColor whiteColor];
- _strokeColor = [UIColor whiteColor];
- _closedIndicatorBackgroundStrokeColor = [UIColor clearColor];
- }
- _animatingLayer.frame = self.bounds;
- [self.layer addSublayer:_animatingLayer];
- // path array
- _paths = [NSMutableArray array];
- // animation duration
- _animationDuration = 0.5;
- }
- - (void)addDisplayLabel
- {
- self.displayLabel = [[RMDisplayLabel alloc] initWithFrame:CGRectMake((CGRectGetWidth(self.bounds)/2 - 30/2), (CGRectGetHeight(self.bounds)/2 - 30/2), 30, 30)];
- self.displayLabel.backgroundColor = [UIColor clearColor];
- self.displayLabel.font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:11.5];
- self.displayLabel.text = @"0";
- self.displayLabel.textColor = [UIColor grayColor];
- self.displayLabel.textAlignment = NSTextAlignmentCenter;
- [self addSubview:self.displayLabel];
- }
- - (void)loadIndicator
- {
- // set the initial Path
- CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
- UIBezierPath *initialPath = [UIBezierPath bezierPath]; //empty path
- if(_type == kRMClosedIndicator)
- {
- [initialPath addArcWithCenter:center radius:(MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))) startAngle:degreeToRadian(-90) endAngle:degreeToRadian(-90) clockwise:YES]; //add the arc
- }
- else
- {
- if(_type == kRMMixedIndictor)
- {
- [self setNeedsDisplay];
- }
- CGFloat radius = (MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))/2) * self.radiusPercent;
- [initialPath addArcWithCenter:center radius:radius startAngle:degreeToRadian(-90) endAngle:degreeToRadian(-90) clockwise:YES]; //add the arc
- }
- _animatingLayer.path = initialPath.CGPath;
- _animatingLayer.strokeColor = _strokeColor.CGColor;
- _animatingLayer.fillColor = _fillColor.CGColor;
- _animatingLayer.lineWidth = _coverWidth;
- self.lastSourceAngle = degreeToRadian(-90);
- }
- #pragma mark -
- #pragma mark Helper Methods
- - (NSArray *)keyframePathsWithDuration:(CGFloat)duration lastUpdatedAngle:(CGFloat)lastUpdatedAngle newAngle:(CGFloat)newAngle radius:(CGFloat)radius type:(RMIndicatorType)type
- {
- NSUInteger frameCount = ceil(duration * 60);
- NSMutableArray *array = [NSMutableArray arrayWithCapacity:frameCount + 1];
- for (int frame = 0; frame <= frameCount; frame++)
- {
- CGFloat startAngle = degreeToRadian(-90);
- CGFloat endAngle = lastUpdatedAngle + (((newAngle - lastUpdatedAngle) * frame) / frameCount);
-
- [array addObject:(id)([self pathWithStartAngle:startAngle endAngle:endAngle radius:radius type:type].CGPath)];
- }
- return [NSArray arrayWithArray:array];
- }
- - (UIBezierPath *)pathWithStartAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle radius:(CGFloat)radius type:(RMIndicatorType)type
- {
- BOOL clockwise = startAngle < endAngle;
- UIBezierPath *path = [UIBezierPath bezierPath];
- CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
- if(type == kRMClosedIndicator)
- {
- [path addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:clockwise];
- }
- else
- {
- [path moveToPoint:center];
- [path addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:clockwise];
- [path closePath];
- }
- return path;
- }
- - (void)drawRect:(CGRect)rect
- {
- if(_type == kRMMixedIndictor)
- {
- CGFloat radius = MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))/2 - self.coverWidth;
-
- CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
- UIBezierPath *coverPath = [UIBezierPath bezierPath]; //empty path
- [coverPath setLineWidth:_coverWidth];
- [coverPath addArcWithCenter:center radius:radius startAngle:0 endAngle:2*M_PI clockwise:YES]; //add the arc
-
- [_strokeColor set];
- [coverPath stroke];
- }
- else if (_type == kRMClosedIndicator)
- {
- CGFloat radius = (MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))/2) - self.coverWidth;
-
- CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
- UIBezierPath *coverPath = [UIBezierPath bezierPath]; //empty path
- [coverPath setLineWidth:_coverWidth];
- [coverPath addArcWithCenter:center radius:radius startAngle:0 endAngle:2*M_PI clockwise:YES]; //add the arc
- [_closedIndicatorBackgroundStrokeColor set];
- [coverPath setLineWidth:self.coverWidth];
- UIColor *fillColor = [UIColor clearColor];
- [fillColor setFill];
- [coverPath fill];
- [coverPath stroke];
- }
- }
- #pragma mark - update indicator
- - (void)updateWithTotalBytes:(CGFloat)bytes downloadedBytes:(CGFloat)downloadedBytes
- {
- _lastUpdatedPath = [UIBezierPath bezierPathWithCGPath:_animatingLayer.path];
- [_paths removeAllObjects];
- CGFloat destinationAngle = [self destinationAngleForRatio:(downloadedBytes/bytes)];
- CGFloat radius = (MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)) * _radiusPercent) - self.coverWidth;
- [_paths addObjectsFromArray:[self keyframePathsWithDuration:self.animationDuration lastUpdatedAngle:self.lastSourceAngle newAngle:destinationAngle radius:radius type:_type]];
- _animatingLayer.path = (__bridge CGPathRef)((id)_paths[(_paths.count -1)]);
- self.lastSourceAngle = destinationAngle;
- CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
- [pathAnimation setValues:_paths];
- [pathAnimation setDuration:self.animationDuration];
- [pathAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
- [pathAnimation setRemovedOnCompletion:YES];
- [_animatingLayer addAnimation:pathAnimation forKey:@"path"];
- //[self.displayLabel updateValue:downloadedBytes/bytes];
- }
- - (CGFloat)destinationAngleForRatio:(CGFloat)ratio
- {
- return (degreeToRadian((360*ratio) - 90));
- }
- float degreeToRadian(float degree)
- {
- return ((degree * M_PI)/180.0f);
- }
- #pragma mark -
- #pragma mark Setter Methods
- - (void)setFillColor:(UIColor *)fillColor
- {
- if(_type == kRMClosedIndicator)
- _fillColor = [UIColor clearColor];
- else
- _fillColor = fillColor;
- }
- - (void)setRadiusPercent:(CGFloat)radiusPercent
- {
- if(_type == kRMClosedIndicator)
- {
- _radiusPercent = 0.5;
- return;
- }
-
- if(radiusPercent > 0.5 || radiusPercent < 0)
- return;
- else
- _radiusPercent = radiusPercent;
- }
- - (void)setIndicatorAnimationDuration:(CGFloat)duration
- {
- self.animationDuration = duration;
- }
- @end
|