2008-08-18 26 views
3

對於我的應用程序的一部分,我需要創建特定視圖及其所有子視圖的圖像。在Cocoa中繪製視圖層次結構到特定的上下文

要做到這一點,我創建了一個包裝與視圖大小相同的位圖的上下文,但我不確定如何繪製視圖層次結構。我可以繪製一個單一的視圖,只需設置上下文並明確調用drawRect,但這並不涉及所有的子視圖。

我不能在NSView界面看到任何可以幫助解決這個問題的東西,所以我懷疑解決方案可能在更高的層面。

回答

2

我發現,寫繪圖代碼自己是最好的辦法:

  • 處理潛在的透明度問題(一些其他的選項都在白色背景上增加了整幅畫面)
  • 表現好得多

下面的代碼並不完美,因爲它不處理從邊界到幀的擴展問題,但它確實考慮了isFlipped狀態,並且對於我使用它的工作非常好。請注意,它只繪製子視圖(和子視圖,...遞歸),但是讓它也可以很容易繪製,只需在imageWithSubviews的實現中添加[self drawRect:[self bounds]]即可。

- (void)drawSubviews 
{ 
    BOOL flipped = [self isFlipped]; 

    for (NSView *subview in [self subviews]) { 

     // changes the coordinate system so that the local coordinates of the subview (bounds) become the coordinates of the superview (frame) 
     // the transform assumes bounds and frame have the same size, and bounds origin is (0,0) 
     // handling of 'isFlipped' also probably unreliable 
     NSAffineTransform *transform = [NSAffineTransform transform]; 
     if (flipped) { 
      [transform translateXBy:subview.frame.origin.x yBy:NSMaxY(subview.frame)]; 
      [transform scaleXBy:+1.0 yBy:-1.0]; 
     } else 
      [transform translateXBy:subview.frame.origin.x yBy:subview.frame.origin.y]; 
     [transform concat]; 

     // recursively draw the subview and sub-subviews 
     [subview drawRect:[subview bounds]]; 
     [subview drawSubviews]; 

     // reset the transform to get back a clean graphic contexts for the rest of the drawing 
     [transform invert]; 
     [transform concat]; 
    } 
} 

- (NSImage *)imageWithSubviews 
{ 
    NSImage *image = [[[NSImage alloc] initWithSize:[self bounds].size] autorelease]; 
    [image lockFocus]; 
    // it seems NSImage cannot use flipped coordinates the way NSView does (the method 'setFlipped:' does not seem to help) 
    // Use instead an NSAffineTransform 
    if ([self isFlipped]) { 
     NSAffineTransform *transform = [NSAffineTransform transform]; 
     [transform translateXBy:0 yBy:NSMaxY(self.bounds)]; 
     [transform scaleXBy:+1.0 yBy:-1.0]; 
     [transform concat]; 
    } 
    [self drawSubviews]; 
    [image unlockFocus]; 
    return image; 
} 
2

您可以使用-[NSView dataWithPDFInsideRect:]將您發送的視圖的整個層次結構呈現爲PDF,並作爲NSData對象返回。然後你可以用它做任何你想做的事情,包括把它渲染成位圖。

您確定要使用位圖嗎?畢竟,PDF可能(至少在理論上)是獨立於分辨率的。

0

是的,對於這種特定的用法,未縮放的圖像數據正是我所需要的。

1

將焦點鎖定在視圖上後,您可以使用-[NSBitmapImageRep initWithFocusedViewRect:]將視圖呈現給給定的矩形(及其子視圖)。

+0

如果視圖位於NSScrollView中,這會產生顯示視圖的副作用內容裁剪爲在滾動視圖中可見的內容,幷包含任何滾動條。 – Jason 2015-09-22 22:21:34

1

你想要做的事情已經明確提供。請參閱10.4 AppKit發行說明中的​​「NSView繪圖重定向API」一節。

做一個NSBitmapImageRep緩存和清除:

NSGraphicsContext *bitmapGraphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:cacheBitmapImageRep]; 
[NSGraphicsContext saveGraphicsState]; 
[NSGraphicsContext setCurrentContext:bitmapGraphicsContext]; 
[[NSColor clearColor] set]; 
NSRectFill(NSMakeRect(0, 0, [cacheBitmapImageRep size].width, [cacheBitmapImageRep size].height)); 
[NSGraphicsContext restoreGraphicsState]; 

緩存它:如果您想更普遍繪製到指定的範圍內正確處理視圖遞歸和透明度

-[NSView cacheDisplayInRect:toBitmapImageRep:] 

-[NSView displayRectIgnoringOpacity:inContext:] 
+0

「NSView繪圖重定向API」的鏈接10.4 http://developer.apple.com/mac/library/releasenotes/Cocoa/AppKitOlderNotes.html – 2010-02-26 01:15:34