setNeedsDisplay不调用drawRect

时间:2013-05-23 14:38:30

标签: ios objective-c

我正在尝试创建循环进度指示器。不幸的是,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。在此先感谢您的帮助。

3 个答案:

答案 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。