2012-05-23 12 views
7

Hosty NSView z warstwami (w takim przypadku NSView, dla których dostarczono instancję CALayer i ustawiono ją na setLayer:), mogą oczywiście zawierać widoki podrzędne. Dlaczego oczywiście? Bo w Apple własny Cocoa Slides sample code project, można sprawdzić pole wyboru, które przełącza AssetCollectionView przed warstwa oparciem do bycia warstwa hosting:Czy NSView z hostami warstwowymi mogą mieć subviews?

- (void)setUsesQuartzCompositionBackground:(BOOL)flag { 
    if (usesQuartzCompositionBackground != flag) { 
     usesQuartzCompositionBackground = flag; 

     /* We can display a Quartz Composition in a layer-backed view tree by 
      substituting our own QCCompositionLayer in place of the default automanaged 
      layer that AppKit would otherwise create for the view. Eventually, hosting of 
      QCViews in a layer-backed view subtree may be made more automatic, rendering 
      this unnecessary. To minimize visual glitches during the transition, 
      temporarily suspend window updates during the switch, and toggle layer-backed 
      view rendering temporarily off and back on again while we prepare and set the 
      layer. 
     */ 
     [[self window] disableScreenUpdatesUntilFlush]; 
     [self setWantsLayer:NO]; 
     if (usesQuartzCompositionBackground) { 
      QCCompositionLayer *qcLayer = [QCCompositionLayer compositionLayerWithFile:[[NSBundle mainBundle] pathForResource:@"Cells" ofType:@"qtz"]]; 
      [self setLayer:qcLayer]; 
     } else { 
      [self setLayer:nil]; // Discard the QCCompositionLayer we were using, and let AppKit automatically create self's backing layer instead. 
     } 
     [self setWantsLayer:YES]; 
    } 
} 

W tym samym AssetCollectionView klasie subviews są dodawane do każdego obrazu, który powinien być wyświetlany:

- (AssetCollectionViewNode *)insertNodeForAssetAtIndex:(NSUInteger)index { 
    Asset *asset = [[[self assetCollection] assets] objectAtIndex:index]; 
    AssetCollectionViewNode *node = [[AssetCollectionViewNode alloc] init]; 
    [node setAsset:asset]; 
    [[self animator] addSubview:[node rootView]]; 
    [nodes addObject:node]; 

    return [node autorelease]; 
} 

Kiedy buduję i uruchamiam aplikację i bawię się nią, wszystko wydaje się być w porządku.

Jednak w Apple's NSView Class Reference for the setWantsLayer: method czyta:

Przy użyciu widoku warstwy hosting nie należy polegać na widoku dla rysunku, ani nie należy dodawać subviews do widoku warstwy-gospodarzem.

Co jest prawdą? Czy przykładowy kod jest niepoprawny i to tylko zbieg okoliczności, że działa? Czy też dokumentacja jest fałszywa (w co wątpię)? Czy jest to w porządku, ponieważ subviews są dodawane za pośrednictwem proxy animatora?

Odpowiedz

19

Kiedy AppKit jest "hostowaniem warstw" zakładamy, że możesz (lub nie) mieć całe podtekst warstw, o których AppKit nie wie.

Po dodaniu widoku podrzędnego do widoku hostowanego w warstwie może on nie zostać wyświetlony we właściwej kolejności w kolejności zgodnej z rodzajem. Dodatkowo czasami je dodajemy i usuwamy, więc może się zmieniać w zależności od tego, kiedy wywołujemy metodę setLayer :, setWantsLayer: lub kiedy widok jest dodawany lub usuwany z superview. Na Lion (i wcześniej) usuwamy warstwy, które "posiadamy" (tj.: Warstwa z kopią), gdy widok jest usuwany z okna (lub superview).

Jest w porządku, aby dodać subviews ... ich kolejność rodzeństwa-dziecko w tablicy podwarstw może być niedeterministyczna, jeśli masz siostrzane warstwy, które nie są NSView.

+0

Dziękuję bardzo bardzo mocno! –

1

Nie wiem, jaka jest "właściwa" odpowiedź na to pytanie. Ale myślę, że przykład CocoaSlides działa w granicach tego, co mówią doktorzy "nie powinieneś" robić. W tym przykładzie spójrz na miejsce, w którym wywoływana jest metoda insertNodeForAssetAtIndex:, a zobaczysz, że dzieje się tak tylko wtedy, gdy widok jest zapełniany, , zanim zostanie przypisana do warstwy lub wywołał ją setWantsLayer:.

Dokumenty nie mówią, że widok obsługiwany przez warstwy nie może zawierać żadnych subskrybentów, po prostu mówią, że nie można dodać i subviews do jednego. W momencie dodania tych widoków główny widok nie stał się jeszcze widokiem warstwy. Po przekształceniu go w widok hostingu warstw poprzez przypisanie do niego ręcznie utworzonej warstwy, nie są dodawane żadne dodatkowe widoki.

Tak naprawdę nie ma sprzeczności między dokumentami i tym konkretnym przykładem. Biorąc to pod uwagę, interesujące może być zbadanie tego dalej, być może poprzez włączenie warstwy tła QC od samego początku, np. przez przyklejenie [self setUsesQuartzCompositionBackground:YES]; bezpośrednio do wnętrza initWithFrame:.

SPOLIER ALERT: Wydaje się działać dobrze. Stworzenie wyświetlacza jest nieco wolniejsze (co nie zaskakuje w przypadku całej animacji QC), ale poza tym jest to płynne żeglarstwo.

+0

Dzięki, Jack! Interesująca obserwacja o "dodawaniu" do "już posiadających" subviews. Być może dokumenty są nieaktualne, ponieważ dotyczą również tego pytania: http://stackoverflow.com/questions/10720062/are-layer-backed-nsview-siblings-allowed-to-overlap/10720422#10720422 –

0

Jedna uwaga na temat tego kodu firmy Apple: jest zepsuta.

Po pierwszym uruchomieniu aplikacji zanotuj ładne tło gradientowe. Włącz QC, a następnie wyłącz.

Puf, bez tła gradientowego.

Powiązane problemy