我试图了解copyOnScroll 在典型的 NSScrollView/NSClipView/NSView 设置中的行为。我将自始至终将 NSView 或 documentView 称为 MyCustomView,并注意这是一个大视图,可能需要大量时间来绘制(我实际上是在示例应用程序中执行此操作,以更好地理解此处的所有各种问题) . 另请注意,我目前正在研究“非层支持案例”,而不是选择响应式滚动。假设视图是 10,000 x 800 单位。还假设这个滚动视图占据了整个窗口,我们只是在一个 1,500 x 800 的窗口中查看 MyCustomView 的开始部分(所以我们正在查看 rect (l: 0, t:0, r:1500, b:800))。现在让我们将所有内容向左滚动 500,以便我们现在查看 (l:500, t:0, r:2000, b:800)。在这样的卷轴中,
根据copyOnScroll上的Apple文档:
当此属性的值为 YES 时,剪辑视图在滚动时复制其现有的渲染图像(仅绘制其文档视图的暴露部分);当它为 NO 时,视图会强制每次重绘其内容。
值得一提的是,当我们的应用程序(真正的应用程序,而不是这个示例应用程序)曾经是基于 Carbon 的应用程序时,这是我们在滚动时看到的行为,更新区域将仅包含可见区域的新暴露部分。
为了进一步了解这种行为,我用 MyScrollView/MyClipView 子类替换了设置的 NSScrollView/NSClipView 部分。覆盖一些例程并仅调用 super 以了解谁在调用各种更新例程(如 setNeedsDisplay 或 setNeedsDisplayInRect :) 我发现以下内容:
单击滚动条开始向右滚动时,我收到以下对 MyClipView::setNeedsDisplayInRect:(NSRect)invalidRect 的调用: invalidRect NSRect (origin = (x = 0, y = 0), size = (width = 0) , height = 0))
invalidRect NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
然后: invalidRect NSRect (origin = (x = 180.5, y = 0), size = (width = 460, height = 363))
这显然是由于 translateOriginToPoint 调用而使整个 visibleRect 失效。这是堆栈:
0 0x0000000100001008 in -[MyClipView setNeedsDisplayInRect:] MyClipView.m:31
1 0x00007fff533ff139 in -[NSView setNeedsDisplay:] ()
2 0x0000000100000fe1 in -[MyClipView setNeedsDisplay:] MyClipView.m:26
3 0x00007fff534f97b4 in -[NSView translateOriginToPoint:] ()
4 0x00007fff538cd6eb in -[NSClipView _nonLayerBackedImmediateScrollToPoint:] ()
5 0x00007fff534f9405 in -[NSClipView _immediateScrollToPoint:] ()
6 0x00007fff538cecbc in -[NSScrollAnimationHelper _doAnimationStepWithProgress:] ()
7 0x00007fff538cebca in -[NSScrollAnimationHelper _doAnimationStep] ()
8 0x00007fff53830f8d in _NSAnimationHelperTimerCallback ()
9 0x00007fff55e8f064 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
10 0x00007fff55e8ecd7 in __CFRunLoopDoTimer ()
11 0x00007fff55e8e7da in __CFRunLoopDoTimers ()
12 0x00007fff55e85dab in __CFRunLoopRun ()
13 0x00007fff55e851a3 in CFRunLoopRunSpecific ()
14 0x00007fff5516dd96 in RunCurrentEventLoopInMode ()
15 0x00007fff5516db06 in ReceiveNextEventCommon ()
16 0x00007fff5516d884 in _BlockUntilNextEventMatchingListInModeWithFilter ()
17 0x00007fff53420a73 in _DPSNextEvent ()
18 0x00007fff53bb6e34 in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] ()
19 0x00007fff53b3adc7 in -[NSScroller trackPagingArea:] ()
20 0x00007fff53b3b2e7 in -[NSScroller mouseDown:] ()
21 0x00007fff53d57d6d in -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] ()
22 0x00007fff53d549c4 in -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] ()
23 0x00007fff53d53c70 in -[NSWindow(NSEventRouting) sendEvent:] ()
24 0x00007fff53bb5236 in -[NSApplication(NSEvent) sendEvent:] ()
25 0x00007fff534158b5 in -[NSApplication run] ()
26 0x00007fff533e4a72 in NSApplicationMain ()
27 0x0000000100003a42 in main main.m:12
28 0x00007fff7e1a9015 in start ()
然后: invalidRect NSRect (origin = (x = 460, y = 0), size = (width = 180.5, height = 363))
这看起来像是要绘制的正确的新“显示”部分。这是堆栈:
0 0x0000000100001008 in -[MyClipView setNeedsDisplayInRect:] at MyClipView.m:31
1 0x00007fff538cdf90 in -[NSClipView _nonLayerBackedImmediateScrollToPoint:] ()
2 0x00007fff534f9405 in -[NSClipView _immediateScrollToPoint:] ()
3 0x00007fff538cecbc in -[NSScrollAnimationHelper _doAnimationStepWithProgress:] ()
4 0x00007fff538cebca in -[NSScrollAnimationHelper _doAnimationStep] ()
5 0x00007fff53830f8d in _NSAnimationHelperTimerCallback ()
6 0x00007fff55e8f064 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
7 0x00007fff55e8ecd7 in __CFRunLoopDoTimer ()
8 0x00007fff55e8e7da in __CFRunLoopDoTimers ()
9 0x00007fff55e85dab in __CFRunLoopRun ()
10 0x00007fff55e851a3 in CFRunLoopRunSpecific ()
11 0x00007fff5516dd96 in RunCurrentEventLoopInMode ()
12 0x00007fff5516da0f in ReceiveNextEventCommon ()
13 0x00007fff5516d884 in _BlockUntilNextEventMatchingListInModeWithFilter ()
14 0x00007fff53420a73 in _DPSNextEvent ()
15 0x00007fff53bb6e34 in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] ()
16 0x00007fff53415885 in -[NSApplication run] ()
17 0x00007fff533e4a72 in NSApplicationMain ()
18 0x0000000100003a42 in main at main.m:12
19 0x00007fff7e1a9015 in start ()
然后还有 3 个: invalidRect NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
invalidRect NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
invalidRect NSRect (origin = (x = 0, y = 0), size = (width = 0, height = 0))
最终 MyCustomView drawRect 用dirtyRect调用:dirtyRect NSRect (origin = (x = 180.5, y = 0), size = (width = 460, height = 363)) 而不是期望的:dirtyRect NSRect (origin = (x = 460, y = 0), 大小 = (宽度 = 180.5, 高度 = 363))
所以知道为什么copysOnScroll不发送适当较小的dirtyRect(或通过getRectsBeingDrawn的较小矩形列表)吗?这种额外的绘图会在实际应用程序中导致严重的性能问题。