首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >setNeedsDisplayInRect:更新整个视图

setNeedsDisplayInRect:更新整个视图
EN

Stack Overflow用户
提问于 2012-05-07 22:56:41
回答 4查看 5.3K关注 0票数 10

我正在开发一个使用CoreGraphics进行渲染的绘画应用程序。我的问题是,为了提高性能,我试图将更新限制在视图中已更改的特定部分。为此,我使用了setNeedsDisplayInRect:,但有时视图会更新它的整个内容,从而导致卡顿。这在第三代iPads上尤其明显,但在模拟器和iPad2中也会发生较小程度的变化。我正在尝试删除此行为。

为了展示这个问题,我使用Xcode中的模板创建了一个简单的“单视图”项目。创建了一个自定义的UIView子类,我在xib文件中将其设置为视图控制器的视图。

将此代码添加到UIViewController中:

代码语言:javascript
复制
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // Asks that the view refreshes a smal rectangle
    [self.view setNeedsDisplayInRect:CGRectMake(10, 10, 20, 20)];
}

将此添加到MyView (我的自定义视图):

代码语言:javascript
复制
- (void)drawRect:(CGRect)rect
{
    // Just log what is being updated
    NSLog(@"%@", NSStringFromCGRect(rect));
}

就是这样。如果我在3th ten iPad (实际的设备)上运行该应用程序,日志会显示视图不时地重新绘制自身(就像非常频繁地)。这太让人沮丧了,我也没办法了

更新:这里有一些日志。它肯定会显示有时正在更新的完整视图。我试着让它完全停止,但不知道如何…

代码语言:javascript
复制
2012-05-04 08:34:01.851 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.184 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.197 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.215 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.226 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.242 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.258 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.274 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.290 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.306 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.322 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.338 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.354 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.371 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.387 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.403 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.419 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:30.439 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:34:30.457 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}

此外,如果我停止移动超过10秒左右,然后继续移动,它肯定会非常一致地这样做:

代码语言:javascript
复制
2012-05-04 08:34:33.305 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:34:33.321 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
2012-05-04 08:35:00.202 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:35:00.221 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:35:00.234 TestUpdateArea[45745:707] {{0, 0}, {320, 460}}
2012-05-04 08:35:00.251 TestUpdateArea[45745:707] {{10, 10}, {20, 20}}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-05-10 15:36:25

看看这个apple document

他们说:

由于iPhone/iPod touch/iPad更新其屏幕的方式,如果你调用-setNeedsDisplayInRect:-setNeedsDisplay:,整个视图将被重绘。

也是

每个UIView都被视为单个元素。当您通过调用-setNeedsDisplayInRect:-setNeedsDisplay:请求部分或全部重绘时,整个视图将被标记为需要更新。

所以我认为你需要使用子视图来更新整个视图的独立rect。

票数 5
EN

Stack Overflow用户

发布于 2013-05-31 16:47:18

公认的答案是错误的(或者至少是误导性的)。

下面是一个简单的setNeedsDisplayInRect代码示例:按照广告的方式工作:

http://charcoaldesign.co.uk/resources/chalkboard.zip

我怀疑苹果公司的文档试图解释这样一个事实,即在iOS上,每个视图背景图像都被转换为OpenGL纹理,并且整个屏幕每帧都会重新合成。这与您的代码是否必须清除并重绘视图背景纹理的全部内容的问题截然不同。

通过使用setNeedsDisplayInRect:您可以避免昂贵的重绘帧之间不变的内容(它使用核心图形,并且不是硬件加速的)。整个屏幕仍然会被重绘,但这并不重要,因为它是由图形处理器硬件加速的,不像drawRect中的代码:

票数 13
EN

Stack Overflow用户

发布于 2012-05-12 00:32:12

我有一个类似的问题:即希望通过调用setNeedsDisplayInRect只更新UIView的一部分:我传递了一个大小正确的有效CGRect (用断点和日志证明了这一点)。在iOS 4.2.1 (在我的iPhone 3G上)下,UIView保持其原始图像,并只更新CGRect指定的部分,但在iOS 5.1 (在我的iPhone 4S上)下,整个UIView被重新绘制为透明的黑色(我无法理解黑色是如何透明的),之后由CGRect指定的区域被正确绘制。这似乎要么是:苹果方面的错误,他们没有正确地实现setNeedsDisplayInRect:并只是将其传递给setNeedsDisplay:;或者这是一个基于新iOS如何处理与实际屏幕架构的交互的故意决定。无论哪种方式,目前看来,开发人员要么不得不承担每次发生图形更改时更新整个UIView的成本,要么使用一些iOS检测并实现不同的屏幕绘制代码,具体取决于要处理的iOS。

我使用UIView属性clearsContextBeforeDrawing进行了一些测试(根据文档,它应该允许有针对性的绘制操作),但是对于YES和NO,结果是相同的,因此它看起来像是绘制代码的实现。

至于在更新期间CGRect的大小不正确:它是在绘图调用之前还是之后设置的。我在调用setNeedsDisplayInRect:之前设置了CGRect,然后在drawRect方法的最后几行将其设置为CGRectNull (如果系统调用了drawRect方法,则我的代码将不会触发)。返回到代码片段后,我可以看到它是内联设置的,这意味着它是一个系统调用,它正在重新绘制整个UIView,因此CGRect是整个视图的原因。

我会继续深入调查,但我担心,除非苹果披露他们对setNeedsDisplayInRect:进行更改的理由,或者修复明显的漏洞,否则我们可能会考虑为每一次图形更新更新UIView的全部内容(这可能是非常“昂贵”的)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10484291

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档