2012-07-30 47 views
2

我有一個應用程序,它可以在屏幕上記錄音頻並繪製波形(以及其他一些元素)。在錄製時,我想在NSScrollView的containerView中繪製波形。 containerView不斷擴展以適應新的音頻信息,並保持滾動到最後。這種行爲與GarageBand中的滾動視圖在錄製新信息時的行爲完全相同。NSScrollView使用盡可能少的drawRect函數進行常量滾動(和擴展):儘可能調用

雖然我已經想出瞭如何實現這一點,但我的系統似乎在進行滾動時使用了不必要數量的drawRect:調用。什麼是最有效的方式來做到這一點(更新contentView的大小,在擴大的區域上繪製新的內容,並滾動,使結束是可見的?不知何故,一旦containerView是更大的寬度,我最終在每個滾動調用drawRect 5次 - 比滾輪的滾動視圖

文檔視圖明智設置:

[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比滾動視圖小:

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}} 
+0

這並不是真的失去控制。請注意,開頭的每個drawRect調用都會覆蓋整個屏幕區域,而後面的drawRect調用僅覆蓋屏幕區域的一小部分,並且沒有任何重疊。因此,這六個調用實際上比單次調用整個區域的調用更有效**(如果您購買假設{100,100}區域上的drawRect將花費25%的時間作爲{200,200中的drawRect }區域)。 – 2012-08-03 14:08:21

+0

是的,但它每次都重新繪製回0點 - 我只需要在新setFrame調用添加的區域上繪製調用。 – 2012-08-03 18:22:34

+0

我想我正在閱讀日誌的方式,它從來沒有在你提交的第二組中的512左側繪製任何東西。它可能不會被完全優化,但從我所知道的情況來看,那些稍後的drawRect調用只在屏幕的一小部分(前3個是512x188,後面三個是512x512),總而言之,它從不重繪左邊的任何東西屏幕的一部分。 – 2012-08-03 18:57:49

回答

1

在這種實時應用的你應該考慮使用圖層,而不是繪製一個超載的方法的UReview: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]; 

您的容器視圖的圖層將具有與您繪製的波形塊一樣多的子圖層。

圖層非常快,並且由於您已繪製的波形不會更改,因此它們將快速呈現爲位圖並且很好地滾動。

+0

我正在使用圖層 - 但您必須擁有一個NSView才能將內容保存在NSScrollView中 - 據我所知,您不能簡單地在其上繪製圖層。或者,我應該說,你可以,但是你並沒有得到NSScrollView自動提供的所有友好的調整大小的東西。 波形正在用CoreGraphics繪製。但是,爲每件作品創建一個新的CALayer將會成爲一場災難,但這並不能解決我上面提到的任何問題。 – 2012-08-08 06:28:35

+0

一旦圖層數據被存儲到GPU內存中,我認爲它不會降低性能,因此它們是獨立於主線程繪製的。 NSView必須存在,但只能作爲所有圖層的容器。我已經做到了,工作得很好。 - 好吧,調整大小的東西是另一個問題;你可以調整圖層大小,旋轉等等,但是它們可以作爲圖像,如果你需要詳細描述你的波形,你將不得不重新繪製它們。 – 2012-08-08 13:17:27

0

在init中你可以調用[self setwantslayer:YES]; 以這種方式自動ns控件將添加一個CALayer,它將使用chache處理繪製調用。

相關問題