【问题标题】:How do I optimise Cocoa drawing to ensure smooth scrolling如何优化 Cocoa 绘图以确保平滑滚动
【发布时间】:2016-12-22 23:10:52
【问题描述】:

我正在使用标准 Cocoa 绘图 API 在 NSView 上绘制图形。见下图。在滚动视图中的 NSView 上有多个图形。每个图表都有大约 1440 个数据点,并且由于正在进行重绘,滚动性能会有些困难。

有没有什么办法可以保证图形只绘制一次,这样图片就可以流畅的上下滚动了?

此视图用于生成 PDF 输出文件。

除非调整视图大小,否则绘图实际上不需要更改,并且不会发生这种情况,是否有任何方法可以防止视图在滚动期间重绘自身。希望有一个简单的开关来确保视图自己绘制一次并将其保存在内存中!?

基本代码在 NSView 子类 draw() 函数中。

override func draw(_ dirtyRect: NSRect) {

    drawAxis()

    // Only draw the graph axis during live resize
    if self.inLiveResize {
        return
    }

    plot1()
    plot2()
    plot3()
    ...

 }

 func plot1(){

     for value in plot1Data {

        path = NSBezierPath()

        if isFirst {
           path?.move(to: value)
        } else {
           path?.line(to: value)
        }
     }
 }

【问题讨论】:

    标签: macos cocoa draw nsview


    【解决方案1】:

    Apple 在其View Programming Guide: Optimizing View Drawing 文章中提供了相当全面的建议。

    您似乎没有采取最小的步骤来避免绘制不必要的东西。例如,您显示的代码不会检查dirtyRect 以查看给定的图是否完全落在它之外,因此不需要绘制。

    不过,正如那篇文章中所述,您通常可以使用 getRectsBeingDrawn(_:count:) 和/或 needsToDraw(_:) 方法做得更好。

    在某些情况下,滚动视图可以保存已经绘制的内容,因此您的视图不需要重新绘制它。请参阅release notes for Responsive Scrolling。但是,这样做的一个要求是您的视图必须是不透明的。它需要覆盖isOpaque 才能返回true。但是,仅仅声称 是不透明的是不够的。通过在每次调用draw() 时绘制整个脏矩形,您的视图实际上必须是不透明的。您可以在进行其他绘图之前用背景颜色填充脏矩形以满足此要求。

    确保剪辑视图的copiesOnScroll 属性也设置为true。这可以在 IB 中完成(尽管它在此处作为滚动视图的属性呈现)或在代码中完成。默认情况下应该是真的。

    请注意,作为响应式滚动一部分的过度绘制将在空闲时间逐步发生。这将涉及对视图的draw() 方法的重复调用。如果您没有对其进行优化以仅绘制与脏矩形相交的东西,那么这些调用将变得缓慢/昂贵。所以,一定要进行优化。

    【讨论】:

    • 好建议。您还可以查看bitmapImageRepForCachingDisplayInRect:cacheDisplayInRect:toBitmapImageRep: 方法。对于这种特殊情况可能没有必要,但谁知道呢。
    • 谢谢,只创建一次所有“NSBezierPaths”是否有意义,即将它们存储在一个数组中,然后遍历该数组以检查每个路径是否与脏矩形相交如果是这样调用路径'stroke()'方法?
    猜你喜欢
    • 2015-11-09
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2020-06-11
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    相关资源
    最近更新 更多