删除/添加CALayers以进行GPU优化

时间:2009-03-09 13:51:59

标签: cocoa core-animation

我有一个图层支持的视图,我正在尝试添加大小约为300 X 270(以像素为单位)的子图层。

子层的数量可能达到1000到2000,更不用说每个子层再次可扩展到大约4280 X 1500或更多的初学者。

所以问题显然是GPU约束。

在添加大约100个尺寸为300 X 270的子图层后,会出现警告image is too large for GPU, ignoring并且正在弄乱图层显示。

这个问题的解决方案(来自某些邮件列表)是使用CATiledLayer,但由于子层显示器的复杂要求,我无法使用tiledLayer。 / p>

是否有可能删除不属于视图VisibleRect的子层?

我尝试removeFromSuperlayer,然后在需要时添加它,当我尝试添加subLayer时总会出现崩溃。

我该怎么做?

我正在添加子层两次(我需要更改它)但是现在只是为了代码的要点:

-(IBAction)addLayer:(id)sender
{
  Layer *l = [[Layer alloc] init];
  CALayer *layer = [l page];
  [contentArray addObject:page];
  [drawLayer addSublayer:layer];
  [self layout];
}

-(void)layout
{
    NSEnumerator *pageEnumr = [contentArray objectEnumerator];

    float widthMargin = [self frame].size.width;
    CGRect rect;
    float zoom = [self zoomFactor];
    while(obj = [contentEnmr nextObject] )
    {
        [obj setZoomFactor:zoom];
        CALayer *pg =(CALayer *)[obj page] ;
        rect = pg.bounds;

        if ( x + pg.bounds.size.width   > widthMargin  )
        {
            x = xOffset;
            y += rect.size.height + spacing ;

        }
        rect.origin = CGPointMake(x,y);
        [obj changeBounds];

        NSRect VisibleRect = [self visibleRect];
        NSRect result = NSIntersectionRect(VisibleRect,NSRectFromCGRect( rect));
        if( NSEqualRects (result ,NSZeroRect) )
        {
            [pg removeFromSuperlayer];
        }else
        {
            [drawLayer addSublayer:pg];
            [pg setFrame:rect];
            [pg setNeedsDisplay];
        }


        x += ( rect.size.width + spacing);
    }

    NSRect viewRect = [self frame];
    if(viewRect.size.height < ( y + rect.size.height + spacing )  )
        viewRect.size.height = ( y + rect.size.height + spacing) ;

    [self setFrameSize: viewRect.size];

}

@interface Layer : NSObject {
CALayer *page;
}
@property (retain) CALayer *page;

2 个答案:

答案 0 :(得分:1)

查看作为WWDC会议一部分的PhotoScroller应用程序。它演示了如何通过仅加载当前可见的图像部分来缩放和滚动非常大的图像。

另请查看this discussion

答案 1 :(得分:0)

您需要执行NSTableView和UITableView所做的工作,并在可见的rect更改时自行管理层的添加/删除。订阅封闭滚动视图的剪辑视图的boundsDidChange noitification(我假设某些图层在屏幕外的原因是它包含在滚动视图中):

- (void) viewDidMoveToSuperview
{
    NSClipView* clipView = [[self enclosingScrollView] contentView];
    [clipView setPostsBoundsChangedNotifications:YES];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(clipViewBoundsDidChange:)
                                                 name:NSViewBoundsDidChangeNotification
                                               object:clipView];
}

然后编写一个clipViewBoundsDidChange:方法,根据需要添加和删除子图层。您可能还希望缓存和重用无效的图层以减少分配。看看UITableView和NSTableView与他们的dataSource对象交互的方式,以获得有关如何为此设计接口的一些想法。

CATiledLayer解决了这个问题,即层的内容 - 即,无论你设置其内容属性还是直接绘制到图形上下文中。它不会对子层执行此操作,实际上我认为建议您不要将子层添加到CATiledLayer,因为这会干扰其绘制行为。