mirror of
https://github.com/wu736139669/ManagerDemo.git
synced 2026-08-05 05:55:42 +00:00
210 lines
6.2 KiB
Objective-C
Executable File
210 lines
6.2 KiB
Objective-C
Executable File
//
|
|
// MRCircularProgressView.m
|
|
// MRCircularProgressView
|
|
//
|
|
// Created by Jose Luis Martinez de la Riva on 30/01/14.
|
|
//
|
|
// Copyright (c) 2014 http://martinezdelariva.com
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE
|
|
//
|
|
|
|
#import "MRCircularProgressView.h"
|
|
|
|
@interface MRCircularProgressView()
|
|
@property (strong, nonatomic) CAShapeLayer *shapeLayer;
|
|
@property (assign, nonatomic) CGFloat currentProgress;
|
|
@property (assign, nonatomic) CGFloat lastProgress;
|
|
@property (assign, nonatomic) BOOL animated;
|
|
@property (assign, nonatomic) CFTimeInterval duration;
|
|
@end
|
|
|
|
@implementation MRCircularProgressView
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
[self setUp];
|
|
}
|
|
|
|
- (id)initWithFrame:(CGRect)frame
|
|
{
|
|
self = [super initWithFrame:frame];
|
|
if (self) {
|
|
// Initialization code
|
|
[self setUp];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)setUp
|
|
{
|
|
// Init variables
|
|
self.delegate = nil;
|
|
self.currentProgress = 0.0f;
|
|
self.lastProgress = 0.0f;
|
|
self.animated = YES;
|
|
self.progressColor = [UIColor blueColor];
|
|
self.wrapperColor = self.progressColor;
|
|
self.duration = 0.5;
|
|
self.progressArcWidth = 3.0f;
|
|
self.wrapperArcWidth = 1.f;
|
|
}
|
|
|
|
- (void)drawRect:(CGRect)rect
|
|
{
|
|
// Outer circle
|
|
CGRect newRect = ({
|
|
CGRect insetRect = CGRectInset(rect, self.wrapperArcWidth + 0.5f, self.wrapperArcWidth + 0.5f);
|
|
CGRect newRect = insetRect;
|
|
newRect.size.width = MIN(CGRectGetMaxX(insetRect), CGRectGetMaxY(insetRect));
|
|
newRect.size.height = newRect.size.width;
|
|
newRect.origin.x = insetRect.origin.x + (CGRectGetWidth(insetRect) - CGRectGetWidth(newRect)) / 2;
|
|
newRect.origin.y = insetRect.origin.y + (CGRectGetHeight(insetRect) - CGRectGetHeight(newRect)) / 2;
|
|
newRect;
|
|
});
|
|
UIBezierPath *outerCircle = [UIBezierPath bezierPathWithOvalInRect:newRect];
|
|
[self.wrapperColor setStroke];
|
|
outerCircle.lineWidth = self.wrapperArcWidth;
|
|
[outerCircle stroke];
|
|
}
|
|
|
|
- (CGPathRef)progressPath
|
|
{
|
|
// Offset
|
|
CGFloat offset = - M_PI_2;
|
|
|
|
// EndAngle
|
|
CGFloat endAngle = self.currentProgress * 2 * M_PI + offset;
|
|
|
|
// Center
|
|
CGRect rect = self.bounds;
|
|
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
|
|
|
|
// Radius
|
|
CGFloat radius = MIN(center.x, center.y) - self.progressArcWidth / 2;
|
|
|
|
// Inner arc
|
|
UIBezierPath *arcPath = [UIBezierPath bezierPathWithArcCenter:center
|
|
radius:radius
|
|
startAngle:offset
|
|
endAngle:endAngle
|
|
clockwise:1];
|
|
|
|
return arcPath.CGPath;
|
|
}
|
|
|
|
- (void)layoutSubviews
|
|
{
|
|
[super layoutSubviews];
|
|
[self refreshShapeLayer];
|
|
}
|
|
|
|
#pragma mark - Getters methods
|
|
|
|
- (CAShapeLayer *)shapeLayer
|
|
{
|
|
if (!_shapeLayer) {
|
|
_shapeLayer = [CAShapeLayer layer];
|
|
_shapeLayer.lineWidth = self.progressArcWidth;
|
|
_shapeLayer.fillColor = nil;
|
|
_shapeLayer.lineJoin = kCALineJoinBevel;
|
|
_shapeLayer.speed=1.0f;
|
|
[self.layer addSublayer:_shapeLayer];
|
|
}
|
|
|
|
// This will allow the color to be change in the middle of the duration period
|
|
_shapeLayer.strokeColor = self.progressColor.CGColor;
|
|
|
|
return _shapeLayer;
|
|
}
|
|
|
|
#pragma mark - Private methods
|
|
|
|
- (void)refreshShapeLayer
|
|
{
|
|
// Update path
|
|
self.shapeLayer.path = [self progressPath];
|
|
|
|
// Animation
|
|
if (self.currentProgress != self.lastProgress && self.animated) {
|
|
// From value
|
|
CGFloat fromValue = (1 * self.lastProgress) / self.currentProgress;
|
|
|
|
// Animation
|
|
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
|
|
pathAnimation.delegate = self.delegate;
|
|
pathAnimation.duration = self.duration;
|
|
pathAnimation.fromValue = @(fromValue);
|
|
pathAnimation.toValue = @(1.0f);
|
|
[self.shapeLayer addAnimation:pathAnimation forKey:@"strokeEnd"];
|
|
}
|
|
|
|
// Update lastProgress
|
|
self.lastProgress = self.currentProgress;
|
|
}
|
|
|
|
#pragma mark - Public methods
|
|
|
|
- (void)setProgress:(CGFloat)progress animated:(BOOL)animate
|
|
{
|
|
self.currentProgress = MAX(MIN(progress, 1.0f), 0.0f);
|
|
self.animated = animate;
|
|
if (progress==0.0) {
|
|
//means reset been tapped
|
|
self.shapeLayer.speed=1;
|
|
|
|
}
|
|
[self setNeedsLayout];
|
|
}
|
|
|
|
- (void)setProgress:(CGFloat)progress duration:(CFTimeInterval)duration
|
|
{
|
|
|
|
self.duration = duration;
|
|
[self setProgress:progress animated:YES];
|
|
}
|
|
|
|
#pragma mark pause/resume
|
|
-(void)pause
|
|
{
|
|
|
|
|
|
if (self.currentProgress !=0) {
|
|
CFTimeInterval pausedTime = [self.shapeLayer convertTime:CACurrentMediaTime() fromLayer:nil];
|
|
self.shapeLayer.speed = 0.0;
|
|
self.shapeLayer.timeOffset = pausedTime;
|
|
}
|
|
|
|
}
|
|
|
|
-(void)resume
|
|
{
|
|
if (self.shapeLayer.speed==0) {
|
|
CFTimeInterval pausedTime = [self.shapeLayer timeOffset];
|
|
self.shapeLayer.speed = 1.0;
|
|
self.shapeLayer.timeOffset = 0.0;
|
|
self.shapeLayer.beginTime = 0.0;
|
|
CFTimeInterval timeSincePause = [self.shapeLayer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
|
|
self.shapeLayer.beginTime = timeSincePause;
|
|
}
|
|
|
|
}
|
|
|
|
@end
|