NSScrollView常量滚动(和扩展),尽可能少的drawRect:调用

时间:2012-07-30 00:47:39

标签: objective-c macos scroll nsscrollview

我有一个应用程序可以记录音频并在屏幕上绘制波形(以及其他一些元素)。在录制时,我想在NSScrollView的容器视图中绘制波形。 containerView不断扩展以容纳新的音频信息并保持滚动到最后。此行为与记录新信息时GarageBand中的滚动视图的行为完全相同。

虽然我已经想出如何实现这一点,但在进行滚动时,我的系统似乎使用了不必要数量的drawRect:调用。最有效的方法是什么(更新contentView大小,在展开区域绘制新内容,然后滚动以便结束可见?不知何故,一旦containerView宽度较大,我最终会在每个滚动上调用drawRect 5次 - 比scrollView明智的

设置了滚动条的文档视图:

[self.scrollView setDocumentView:self.containerView];

进一步滚动的方法(从NSTimer调用):

- (void)scrollFurther {   
    scrollPoint = ([SSSubdivisionManager manager].lastStartSample + [RemoteIOPlayer remote].diffInFrames) / (zoomLevel * baseZoomLevel);
    int scrollWidth = self.scrollView.frame.size.width;
    CGRect frame = self.containerView.frame;

    if (scrollPoint >= ((scrollPoint + (scrollWidth * 0.5f) ) / 2)) {
        if (![SSAudioManager manager].isDoingInputPlayback) {
            frame.size.width = scrollPoint + (scrollWidth * 0.5f);

            NSLog(@"Setting scroller frame to: %@", NSStringFromRect(frame));

            [self.containerView setFrame:frame];
        }

        NSPoint p = NSMakePoint(scrollPoint - (scrollWidth * 0.5), 0);
        NSLog(@"Scrolling to point %@", NSStringFromPoint(p));
        [self.containerView scrollPoint:p];
    } else {
        NSLog(@"Not exapanding frame or scrolling to a point");
        [self.containerView setNeedsDisplayInRect:frame];
    }
}

结果日志调用:

首先,当containerView小于scrollView:

2012-07-29 17:42:43.607 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{0, 0}, {1924, 700}}
2012-07-29 17:42:43.683 MET[4679:503] Setting scroller frame to: {{0, 0}, {1942.3199462890625, 700}}
2012-07-29 17:42:43.684 MET[4679:503] Scrolling to point {580.3199462890625, 0}
2012-07-29 17:42:43.687 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{0, 0}, {1942, 700}}
2012-07-29 17:42:43.757 MET[4679:503] Setting scroller frame to: {{0, 0}, {1957.6800537109375, 700}}
2012-07-29 17:42:43.758 MET[4679:503] Scrolling to point {595.6800537109375, 0}
2012-07-29 17:42:43.760 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{0, 0}, {1957, 700}}
2012-07-29 17:42:43.835 MET[4679:503] Setting scroller frame to: {{0, 0}, {1975.5999755859375, 700}}
2012-07-29 17:42:43.836 MET[4679:503] Scrolling to point {613.5999755859375, 0}
2012-07-29 17:42:43.839 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{0, 0}, {1975, 700}}
2012-07-29 17:42:43.889 MET[4679:503] Setting scroller frame to: {{0, 0}, {1988.4000244140625, 700}}
2012-07-29 17:42:43.890 MET[4679:503] Scrolling to point {626.4000244140625, 0}
2012-07-29 17:42:43.892 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{0, 0}, {1988, 700}}

然后,它失去控制:

2012-07-29 17:42:43.954 MET[4679:503] Setting scroller frame to: {{0, 0}, {2001.199951171875, 700}}
2012-07-29 17:42:43.956 MET[4679:503] Scrolling to point {639.199951171875, 0}
2012-07-29 17:42:43.960 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1536, 512}, {465.199951171875, 188}}
2012-07-29 17:42:43.961 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1024, 512}, {512, 188}}
2012-07-29 17:42:43.964 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{512, 512}, {512, 188}}
2012-07-29 17:42:43.971 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1536, 0}, {465.199951171875, 512}}
2012-07-29 17:42:43.972 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1024, 0}, {512, 512}}
2012-07-29 17:42:43.977 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{512, 0}, {512, 512}}
2012-07-29 17:42:44.098 MET[4679:503] Setting scroller frame to: {{0, 0}, {2034.47998046875, 700}}
2012-07-29 17:42:44.099 MET[4679:503] Scrolling to point {672.47998046875, 0}
2012-07-29 17:42:44.104 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1536, 512}, {498.47998046875, 188}}
2012-07-29 17:42:44.107 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1024, 512}, {512, 188}}
2012-07-29 17:42:44.112 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{512, 512}, {512, 188}}
2012-07-29 17:42:44.118 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1536, 0}, {498.47998046875, 512}}
2012-07-29 17:42:44.120 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1024, 0}, {512, 512}}
2012-07-29 17:42:44.125 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{512, 0}, {512, 512}}
2012-07-29 17:42:44.154 MET[4679:503] Setting scroller frame to: {{0, 0}, {2047.280029296875, 700}}
2012-07-29 17:42:44.155 MET[4679:503] Scrolling to point {685.280029296875, 0}
2012-07-29 17:42:44.157 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1536, 512}, {511.280029296875, 188}}
2012-07-29 17:42:44.159 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1024, 512}, {512, 188}}
2012-07-29 17:42:44.162 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{512, 512}, {512, 188}}
2012-07-29 17:42:44.168 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1536, 0}, {511.280029296875, 512}}
2012-07-29 17:42:44.172 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{1024, 0}, {512, 512}}
2012-07-29 17:42:44.178 MET[4679:503] -[SSVisualContainer drawRect:] [Line 70] Drawrect: {{512, 0}, {512, 512}}

2 个答案:

答案 0 :(得分:1)

在这种实时应用程序中,您应考虑使用图层而不是绘制到UIView重载 drawRect:方法。

也许你可以使用CoreGraphics函数将每个新的波形绘制成一个位图(非常快,因为它们没有写入显示),然后创建一个新的CALayer,将图像放入其中并将其放置在容器视图的结束坐标。

context = CGBitmapContextCreate(etc...);
// draw your graphic (waveform) into the context
CALayer *newlayer = [CALayer layer];
newlayer.contents = CGBitmapContextCreateImage (context);
newlayer.position = CGPointMake(...at the end of container...);
[container.layer addSublayer: newlayer];

您的容器视图的图层将包含与您绘制的波形块一样多的子图层,一个是另一个。

图层非常快,并且由于您已经绘制的波形不会改变,它们将作为位图快速渲染并滚动得很好。

答案 1 :(得分:0)

在init中你可以调用[self setwantslayer:YES]; 通过这种方式,ns控件将自动添加一个CALayer,它将使用chache处理绘制调用。