Farlanki.

学习DACircularProgress

字数统计: 715阅读时长: 3 min
2016/04/20 Share

DACircularProgress是一个第三方的progressView.

绘制

绘制的工作主要在circularProgressLayer里完成.

- (void)drawInContext:(CGContextRef)context

1
2
3
4
5
6
7
CGMutablePathRef trackPath = CGPathCreateMutable();
CGPathMoveToPoint(trackPath, NULL, centerPoint.x, centerPoint.y);
CGPathAddArc(trackPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(2.0f * M_PI), 0.0f, TRUE);
CGPathCloseSubpath(trackPath);
CGContextAddPath(context, trackPath);
CGContextFillPath(context);
CGPathRelease(trackPath);

绘制背景圆

1
2
3
4
5
6
7
8
9
10
if (progress > 0.0f) {
CGContextSetFillColorWithColor(context, self.progressTintColor.CGColor);
CGMutablePathRef progressPath = CGPathCreateMutable();
CGPathMoveToPoint(progressPath, NULL, centerPoint.x, centerPoint.y);
CGPathAddArc(progressPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(3.0f * M_PI_2), radians, !clockwise);
CGPathCloseSubpath(progressPath);
CGContextAddPath(context, progressPath);
CGContextFillPath(context);
CGPathRelease(progressPath);
}

绘制进度部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (progress > 0.0f && self.roundedCorners) {
CGFloat pathWidth = radius * self.thicknessRatio;
CGFloat xOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * cosf(radians)));
CGFloat yOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * sinf(radians)));
CGPoint endPoint = CGPointMake(xOffset, yOffset);

CGRect startEllipseRect = (CGRect) {
.origin.x = centerPoint.x - pathWidth / 2.0f,
.origin.y = 0.0f,
.size.width = pathWidth,
.size.height = pathWidth
};
CGContextAddEllipseInRect(context, startEllipseRect);
CGContextFillPath(context);

CGRect endEllipseRect = (CGRect) {
.origin.x = endPoint.x - pathWidth / 2.0f,
.origin.y = endPoint.y - pathWidth / 2.0f,
.size.width = pathWidth,
.size.height = pathWidth
};
CGContextAddEllipseInRect(context, endEllipseRect);
CGContextFillPath(context);
}

绘制圆角,具体是绘制一个圆,一般和进度部分重合,这部分看不到,另一部分就有了圆角效果.

1
2
3
4
5
6
7
8
9
10
CGContextSetBlendMode(context, kCGBlendModeClear);
CGFloat innerRadius = radius * (1.0f - self.thicknessRatio);
CGRect clearRect = (CGRect) {
.origin.x = centerPoint.x - innerRadius,
.origin.y = centerPoint.y - innerRadius,
.size.width = innerRadius * 2.0f,
.size.height = innerRadius * 2.0f
};
CGContextAddEllipseInRect(context, clearRect);
CGContextFillPath(context);

清除中间部分
如果没去除去除中间部分,并且吧圆角部分改成红色,就会变成这个样子.

##疑问
- (void)drawInContext:(CGContextRef)context
里输出progress的值

1
NSLog(@"%f",self.progress);

输出如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2016-04-20 22:48:38.968 DACTest[2836:557670] 0.000000
2016-04-20 22:48:38.986 DACTest[2836:557670] 0.025026
2016-04-20 22:48:39.007 DACTest[2836:557670] 0.054017
2016-04-20 22:48:39.025 DACTest[2836:557670] 0.085763
2016-04-20 22:48:39.043 DACTest[2836:557670] 0.125796
2016-04-20 22:48:39.060 DACTest[2836:557670] 0.170546
2016-04-20 22:48:39.080 DACTest[2836:557670] 0.224875
2016-04-20 22:48:39.098 DACTest[2836:557670] 0.275629
2016-04-20 22:48:39.121 DACTest[2836:557670] 0.339246
2016-04-20 22:48:39.139 DACTest[2836:557670] 0.384856
2016-04-20 22:48:39.157 DACTest[2836:557670] 0.423214
2016-04-20 22:48:39.175 DACTest[2836:557670] 0.453805
2016-04-20 22:48:39.193 DACTest[2836:557670] 0.476371
2016-04-20 22:48:39.234 DACTest[2836:557670] 0.499733
2016-04-20 22:48:39.252 DACTest[2836:557670] 0.500000

这是layer的presentationLayerprogess的值,并不是moduleLayerprogress的值,与objccn说的不一样.

-setProgress:animated:

通过调用DACircularProgressView-setProgress:animated:改变进度.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f);
if (animated) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"];
animation.duration = duration;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fillMode = kCAFillModeForwards;
animation.fromValue = [NSNumber numberWithFloat:self.progress];
animation.toValue = [NSNumber numberWithFloat:pinnedProgress];
animation.beginTime = CACurrentMediaTime() + initialDelay;
animation.delegate = self;
[self.circularProgressLayer addAnimation:animation forKey:@"progress"];
} else {
[self.circularProgressLayer setNeedsDisplay];
self.circularProgressLayer.progress = pinnedProgress;
}

这段创建了一个CABasicAnimation对象,CABasicAnimation会为fromValuetoValue之间自动插值.

因为DACircularProgressLayer实现了-needsDisplayForKey:方法,所以当CABasicAnimationprogress的值从fromValuetoValue之间自动变化时,会自动调用-needsDisplayForKey:方法

1
2
3
4
5
6
7
8
+ (BOOL)needsDisplayForKey:(NSString *)key
{
if ([key isEqualToString:@"progress"]) {
return YES;
} else {
return [super needsDisplayForKey:key];
}
}

-needsDisplayForKey:返回true时,-drawInContext:会被调用,上述的绘制过程将被执行.

CATALOG
  1. 1. 绘制
  2. 2. -setProgress:animated: