【问题标题】:Set UIView backgroundColor with drawRect:使用 drawRect 设置 UIView 背景颜色:
【发布时间】:2013-02-24 00:27:27
【问题描述】:

我正在尝试设置自定义 UIView 类的背景颜色。该课程还使用drawRect:method 进行石英绘图。

由于在下次重绘视图之前不会更改背景颜色,因此我在调用 setNeedsDisplay 之前更改了 UIView 的 backgroundColor 属性。我设置了一个UIActivityIndicatorView 以在视图重绘时进行动画处理。

self.backgroundColor = theColor; 
[indicator startAnimating];
[self performSelectorInBackground:@selector(setNeedsDisplay) withObject:nil];

指标在setNeedsDisplay 的末尾停止。 theColor 每次我需要调用它时都会改变。

假设我有一个耗时的setNeedsDisplay 进程。我想设置背景并保留指示器动画。目前,更改backgroundColor 调用setNeedsDisplay,但在performSelectorInBackground 方法运行之前甚至不会更改背景颜色!因此,我的应用程序挂起,并且没有任何指标动画。 我该如何处理这个排序问题?谢谢。

编辑:我的意思是我的drawrect: 可能很耗时。

【问题讨论】:

  • setNeedsDisplay 不耗时,它是drawRect:。但无论如何你都不应该打电话给drawRect:

标签: ios objective-c cocoa performselector setneedsdisplay


【解决方案1】:

假设我有一个耗时的 setNeedsDisplay 过程

我们不要。您没有业务覆盖setNeedsDisplay。我完全不清楚您最终要完成什么,但这整个问题似乎是对如何绘画的误解。当你调用setNeedsDisplay 时(正如你被告知的,你必须在主线程中调用),就是这样;你站在一边,当重绘时刻到来时,你的视图的drawRect:被调用。那就是画画。

如果问题仅仅是活动指示器永远无法启动,那是因为您从未给它机会。在重绘时刻之前它也不会开始。但是您甚至在重绘时刻到来之前就停止了活动指示器!所以很明显你永远看不到它。

在你做下一件事情之前明显地启动一个活动指示器的方法是在下一个重绘时刻之后跳到主线程。这称为“延迟性能”。示例:

self.backgroundColor = theColor; 
[indicator startAnimating];
double delayInSeconds = 0.1;
dispatch_time_t popTime =
    dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // do something further, e.g. call setNeedsDisplay
};

您可以通过再次调用dispatch_after 来扩展该示例,以在下一个重绘时刻之后停止指示器。

但是,我必须让你印象深刻,如果仅仅是绘画动作就需要很长时间,以至于你需要一个活动指示器来覆盖它,那么你就画错了。你的绘画动作必须非常非常快。您可能想观看关于这个主题的 WWDC 2012 视频;它提供了有关如何高效绘图的绝佳技巧。

【讨论】:

  • 对不起,我的意思是我的 drawrect: 方法可能需要一段时间。绘图的复杂性基于用户输入,因此我正在努力为最坏的情况做准备。据我记得,
  • @AnsonL 如果您的 drawrect: 方法需要一段时间,那么您需要将其分解。正如马特所说,有一个关于这个主题的优秀 WWDC2012 视频(尽管在这种情况下,它是关于多线程,而不是绘图)。您需要做的是将绘图工作放在单独的线程上(在 UIImage 而不是实际视图上工作?),然后在完成后将数据移植到主线程以更新 UI。
  • @AnsonL 重读我说的话:不要让我重复自己。您的drawRect: 应该需要一段时间。你必须画。您不需要调度来延迟性能;如果您不了解延迟性能或线程,您可能想阅读我的书:apeth.com/iOSBook/ch38.htmlapeth.com/iOSBook/ch11.html#_delayed_performance。最重要的是观看那些 WWDC 视频;我特别想到 WWDC 2012 会议 235 和 238。
  • @matt 好的,我已经查看了 GCD 文档和您的书。在您的书中,您使用 dispatch_after 延迟 0.1。你说这是为了让指标有时间显示。但是你不能通过使用dispatch_async和自定义dispatch_queue_t来避免0.1的人为延迟以避免阻塞main_queue吗?
  • 我不是在“阻塞 main_queue”。我正在做完全相反的事情:我站在一边,直到主队列完成它正在做的事情(即我正在等待当前的运行循环完成)。
【解决方案2】:

您只能在主线程上更新 UI,而不是在背景中

尝试使用另一个带有活动指示器的子视图,在重绘之前放入并在之后从超级视图中移除

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 2012-10-24
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多