【问题标题】:setNeedsDisplay doesn't always call drawRectsetNeedsDisplay 并不总是调用 drawRect
【发布时间】:2009-05-17 18:02:50
【问题描述】:

我在自定义表格单元格中有一个自定义视图。每次更改自定义视图上的特定属性时,我都会调用[self setNeedsDisplay],它会在- (void)drawRect:(CGRect)rect 中重绘视图。该属性在表视图委托的tableView:cellForRowAtIndexPath: 中设置。但是当表格视图大于屏幕并且必须重复使用单元格时,drawRect 并不是每次都调用setNeedsDisplay。尤其是当我快速轻弹桌子的时候。慢速滚动效果很好。这导致第一个和最后一个单元格中的信息经常不正确。

在日志中我可以看到通常情况下,每次调用setNeedsDisplay 都会调用drawRect,但是当我快速滚动表格视图时,调用setNeedsDisplay 的次数比调用drawRect 的次数要多。当然这里应该是一对一的比例。

我在普通 UIView 中使用相同的自定义视图,每次调用 setNeedsDisplay 时它都会完美重绘。这个问题似乎与表格视图和重用单元格无关。

有人知道这里发生了什么吗? 有没有其他方法可以强制自定义视图重绘自身?

【问题讨论】:

    标签: iphone cocoa-touch


    【解决方案1】:

    在我发现问题之前,我想我已经为这个问题苦苦挣扎了将近一周。在这里,我不骗你:

    指向此自定义视图的指针是在 .m 文件而不是 .h 文件中定义的,使其成为类变量而不是实例变量。

    是的,我非常非常尴尬。

    【讨论】:

      【解决方案2】:

      setNeedsDisplay 只会在视图可见时调用 drawRect:,否则会使视图的层无效,并且在可见时将调用 drawRect:

      在表格视图中滚动时,表格视图将请求单元格以希望将它们添加到视图中。如果滚动速度足够快,则某些单元格的准备时间会过长,并且当它们准备好时,它们应该定位的位置已在屏幕外。在这些情况下,表格视图会丢弃它们而不是将它们添加到滚动视图中(因此不会调用drawRect:

      【讨论】:

      • 另外,setNeedsDisplay 只影响调用它的视图。如有必要,任何子视图都必须独立失效
      • 对于大表来说听起来很合理,但我的表只有 10 行,其中 8 行同时可见。这难道不是仅适用于在重新绘制之前从表格下方移动到表格上方的单元格吗?
      • 是的,这只适用于大表。在您的表格中,所有 8 个可见行都应该收到 drawRect:... 如果不是,那可能是某个地方的错误。您可以发布您的代码(或仍然存在错误的简化版本)吗?
      • 事实证明,即使每次调用 setNeedsDisplay 都会导致调用 drawRect,但自定义视图的内容仍然经常出错。并且当正常滚动时,即将出现的自定义视图通常会在表格另一端已经可见的单元格中重新绘制!这完全没有意义。这个视频 (nottoobadsoftware.com/Repetitions/drawrect_bug.mov) 更好地解释了它。注意底部的第二个单元格。每行顶部都有一个标签,下面有一个自定义视图(自定义视图中的最后一个文本仅用于调试目的)。
      • 有时其他单元格会像这样重绘。顺便说一句:当实际问题发生了如此大的变化时,我应该重写问题还是创建一个新问题?我的意思是标题甚至不再准确。从我的分数可以看出,我是新来的。
      【解决方案3】:

      您应该调用[_table_ reloadData] 来重绘表格。不是[_table_cell_ setNeedsDsiplay]

      【讨论】:

      • 我不会重绘表格。只是自定义视图。
      • reloadData 在适当的时候为您调用 setNeedsDisplay。您似乎正在与框架作斗争。让框架决定更新哪些,然后只实现 tableView:cellForRowAtIndexPath:
      • reloadData 导致表的所有单元格被破坏,数据源被重新查询,可见单元格被重新创建。这比仅刷新单个单元格所需要的要多得多。
      • 感谢您的回答,我在 UITableView 中遇到了问题。我在该自定义单元格中有一个自定义单元格视图和自定义 UIView。用户第二次来时,自定义 UIView 没有调用 drawRect 函数。你的 reloadData 解决了我的问题。
      【解决方案4】:

      听起来视图刷新有两种情况:如果内部值更改(并且您调用[self setNeedsDisplay] 强制更新),以及如果表格视图请求绘制(或重用)单元格.在这种情况下,您没有明确地重绘该自定义视图。

      根据文档:

      tableView:cellForRowAtIndexPath: 中的表视图委托应该始终在重用单元格时重置所有内容。

      如果 tableview 正在回收单元格,它会交还一个仍保留旧值的单元格。确保内容已更新由您决定。根据您设置自定义表格单元格的方式,您可能需要做更多工作以确保视图是最新的,但最简单的方法是在自定义表格单元格处理程序中强制调用 [myCustomView setNeedsDisplay]

      【讨论】:

      • 这就是我正在做的。在 tableView:cellForRowAtIndexPath: 中,我更改了自定义视图的基础数据并在其上调用 setNeedsDisplay。在日志中我可以看到,通常每次调用 setNeedsDisplay 都会调用 drawRect,但是当我快速滚动表格视图时,调用 setNeedsDisplay 的次数比调用 drawRect 的次数多。当然这里应该是一对一的比例。
      • 尝试将单元格滚动出视图并返回以查看更改是否生效。我只记得我去年提交了一份关于这个确切问题的错误报告(错误 #6022064:UITableViews 和更新附件视图)。他们回答说他们无法复制这个错误。在我的例子中,调用了一个导航控制器,它会改变附件视图的颜色,并且会调用 setNeedsDisplay,但是当你返回时,它不会刷新。滚动单元格离开表格并返回将显示正确的颜色。如果它的行为相同并且您可以隔离它,也许您可​​以提交它并欺骗错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多