удаление / добавление CALayers для оптимизации GPU - PullRequest
1 голос
/ 09 марта 2009

У меня есть представление со слоями, я пытаюсь добавить к нему подслои размером примерно 300 X 270 (в пикселях).

Количество подслоев может достигать 1000-2000, не говоря уже о том, что каждый подслой снова масштабируется до примерно 4280 X 1500 или более для начинающих.

Итак, проблема, очевидно, в ограничении графического процессора.

После добавления около 100 подслоев размером 300 X 270 появляется предупреждение image is too large for GPU, ignoring, которое не работает с отображением слоя.

Решением такой проблемы (из некоторых списков рассылки) было использование CATiledLayer, но я не могу использовать tiledLayer из-за сложного требования отображения подуровня.

Есть ли возможность удаления подслоев, которые не попадают под VisibleRect вида?

Я пытался removeFromSuperlayer, а затем добавлял его всякий раз, когда это требовалось, всегда возникал сбой при попытке добавить подслой обратно.

Как я могу это сделать?

Я добавляю подслой дважды (мне нужно изменить его), но пока только для сути кода:

-(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 ]

1 голос
/ 05 октября 2010

Посмотрите на приложение PhotoScroller, входящее в состав конференции WWDC. Он демонстрирует, как масштабировать и прокручивать очень большое изображение, загружая только те части изображения, которые в данный момент видны.

Также проверьте это обсуждение .

0 голосов
/ 19 ноября 2011

Вам нужно будет делать то, что делают NSTableView и UITableView, и самостоятельно управлять добавлением / удалением слоев при каждом изменении видимого прямоугольника. Подпишитесь на уведомление boundsDidChange представления клипа вмещающего представления прокрутки (я предполагаю, что причина того, что некоторый слой является неэкранным, заключается в том, что он заключен в представление прокрутки):

- (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, так как это мешает его поведению при рисовании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...