我正在尝试创建循环进度指示器。不幸的是,drawRect例程仅从setNeedsDisplay调用第一次和最后一次,它不会创建我正在寻找的渐进填充模式。我已经创建了一个UIView子类,我在其中填充背景,然后按如下方式更新绘制进度:
- (void)drawRect:(CGRect)rect
{
// draw background
CGFloat lineWidth = 5.f;
UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath];
processBackgroundPath.lineWidth = lineWidth;
processBackgroundPath.lineCapStyle = kCGLineCapRound;
CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.width / 2);
CGFloat radius = (self.bounds.size.width - lineWidth) / 2;
CGFloat startAngle = (2 * (float)M_PI / 2); // 90 degrees
CGFloat endAngle = (2 * (float)M_PI) + startAngle;
[processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
[[UIColor grayColor] set];
[processBackgroundPath stroke];
// draw progress
UIBezierPath *processPath = [UIBezierPath bezierPath];
processPath.lineCapStyle = kCGLineCapRound;
processPath.lineWidth = lineWidth;
endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
[processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
[[UIColor blackColor] set];
[processPath stroke];
}
我使用以下方法设置进度变量:
- (void)setProgress:(float)progress {
_progress = progress;
[self setNeedsDisplay];
}
然后,在将具有上述类的UIView分配给我的故事板后,我只需在我的主视图控制器中调用附加方法:
- (void)progressView:(CircularProgress *)activityView loopTime:(CGFloat)duration repeats:(BOOL)repeat {
float portion = 0.0f;
while (portion < 1.0f) {
portion += 1/ (20.0 * duration);
[activityView setProgress:portion];
usleep(50000);
}
}
同样,[self setNeedsDisplay]仅在第一次和最后一次调用drawRect。在此先感谢您的帮助。
答案 0 :(得分:5)
usleep(50000)
阻止线程
使用NSTimer
代替更新progressView。
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(updateProgressView) userInfo:nil repeats:YES];
duration = 0;
...
- (void)updateProgressView {
// Update the progress
}
}
...
答案 1 :(得分:1)
作为NSTimer
的替代方案,我还建议您使用CADisplayLink
:
CADisplayLink对象是一个允许您的应用程序的计时器对象 将其绘图与显示器的刷新率同步。
您的应用程序会创建一个新的显示链接,提供目标对象 以及更新屏幕时要调用的选择器。接下来,你的 应用程序将显示链接添加到运行循环。
一旦显示链接与运行循环相关联,选择器就会打开 当需要更新屏幕内容时调用目标。
这将确保您的进度视图大致与设备帧速率同步重绘。
答案 2 :(得分:0)
您的drawRect:
和progressView:…
方法都将在主线程上调用。
setNeedsDisplay:
未立即致电drawRect:
;它将其排队等待下次应用程序的主线程通过其运行循环时调用。使用NSTimer
或阅读CoreAnimation以查看它是否提供了更直接适用的内容:您当前的解决方案将消耗大量CPU时间,并且不会利用GPU。