Ios setNeedsDisplay未调用drawRect
我正在尝试创建一个循环进度指示器。不幸的是,drawRect例程仅在setNeedsDisplay的第一次和最后一次调用,这并没有创建我正在寻找的渐变填充模式。我已经创建了一个UIView子类,在其中填充背景,然后更新绘制进度,如下所示:Ios setNeedsDisplay未调用drawRect,ios,objective-c,Ios,Objective C,我正在尝试创建一个循环进度指示器。不幸的是,drawRect例程仅在setNeedsDisplay的第一次和最后一次调用,这并没有创建我正在寻找的渐变填充模式。我已经创建了一个UIView子类,在其中填充背景,然后更新绘制进度,如下所示: - (void)drawRect:(CGRect)rect { // draw background CGFloat lineWidth = 5.f; UIBezierPath *processBackgroundPath = [UIB
- (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分配给我的故事板后,我只需在我的主viewcontroller中调用附加的方法:
- (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);
}
}
-(void)progressView:(CircularProgress*)活动视图loopTime:(CGFloat)持续时间重复:(BOOL)重复{
浮动部分=0.0f;
而(部分<1.0f){
部分+=1/(20.0*持续时间);
[活动视图设置进度:部分];
美国LEEP(50000);
}
}
同样,[self-setNeedsDisplay]只在第一次和最后一次调用drawRect。提前感谢您的帮助。usleep(50000)
阻止线程
使用NSTimer
更新progressView
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(updateProgressView) userInfo:nil repeats:YES];
duration = 0;
...
- (void)updateProgressView {
// Update the progress
}
}
...
usleep(50000)
阻塞线程
使用NSTimer
更新progressView
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(updateProgressView) userInfo:nil repeats:YES];
duration = 0;
...
- (void)updateProgressView {
// Update the progress
}
}
...
将在主线程上调用
drawRect:
和progressView:…
方法
setNeedsDisplay:
不会立即调用drawRect:
;它将其排队,以便下次应用程序的主线程通过其运行循环时调用。使用NSTimer
或阅读CoreAnimation,看看它是否提供了更直接适用的内容:您当前的解决方案将占用大量CPU时间,并且不会利用GPU。您的drawRect:
和progressView:…
方法都将在主线程上调用
setNeedsDisplay:
不会立即调用drawRect:
;它将其排队,以便下次应用程序的主线程通过其运行循环时调用。使用NSTimer
或阅读CoreAnimation,看看它是否提供了更直接适用的功能:您当前的解决方案将占用大量CPU时间,并且不会利用GPU。作为NSTimer
的替代方案,我还建议使用:
CADisplayLink对象是允许应用程序运行的计时器对象
将其图形与显示的刷新率同步
应用程序创建一个新的显示链接,提供一个目标对象
以及在屏幕更新时调用的选择器。接下来,你的
应用程序将显示链接添加到运行循环
显示链接与运行循环关联后,选择器将打开
当需要更新屏幕内容时,调用目标
这将确保重新绘制进度视图时与设备帧速率大致同步。作为
NSTimer
的替代方法,我还建议使用:
CADisplayLink对象是允许应用程序运行的计时器对象
将其图形与显示的刷新率同步
应用程序创建一个新的显示链接,提供一个目标对象
以及在屏幕更新时调用的选择器。接下来,你的
应用程序将显示链接添加到运行循环
显示链接与运行循环关联后,选择器将打开
当需要更新屏幕内容时,调用目标
这将确保重新绘制进度视图时与设备帧速率大致同步。谢谢您的回复。我用计时器和方法替换了原来的方法,该方法增加计数器并在自定义视图上调用setProgress方法。不幸的是,我仍然有同样的问题。欢迎您的建议。谢谢您的回复。我用计时器和方法替换了原来的方法,该方法增加计数器并在自定义视图上调用setProgress方法。不幸的是,我仍然有同样的问题。接受建议。这是唯一有效的解决方案。非常感谢。这里有一个很好的例子。非常感谢!!!这是唯一有效的解决方案。非常感谢。这里有一个很好的例子。非常感谢!!!