7

托管层的 NSView(因此您提供 CALayer 实例并设置它的 NSView setLayer:)显然可以包含子视图。为什么很明显?因为在 Apple 自己的Cocoa Slides 示例代码项目中,您可以选中一个复选框,将其AssetCollectionView从 layer-backed 切换为 layer-hosting:

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

在同一个AssetCollectionView类中,为每个应该显示的图像添加子视图:

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

当我构建并运行应用程序并使用它时,一切似乎都很好。

但是,在Apple 的 NSView 类参考中,setWantsLayer:它读取的方法是:

使用图层托管视图时,您不应依赖视图进行绘图,也不应将子视图添加到图层托管视图。

什么是真的?示例代码是否不正确,它的工作原理只是巧合?或者文件是假的(我怀疑)?还是因为子视图是通过动画代理添加的?

4

3 回答 3

19

当 AppKit 是“层托管”时,我们假设您可能(或可能没有)拥有 AppKit 不知道的整个层子树。

如果您将子视图添加到图层托管视图,则它可能不会以您想要的正确同级顺序出现。另外,我们有时会添加和删除它们,因此它可能会根据您何时调用 setLayer:、setWantsLayer: 或何时从父视图中添加或删除视图而改变。在 Lion(和之前)上,当视图从窗口(或超级视图)中移除时,我们会移除我们“拥有”的层(即:支持层)。

添加子视图是可以的……如果您有不是 NSViews 的兄弟层,它们在子层数组中的子兄弟顺序可能不是确定性的。

于 2012-05-23T23:24:57.777 回答
1

我不知道这个问题的“正确”答案是什么。但我确实认为 CocoaSlides 示例在文档说你“不应该”做的范围内有效。在示例中,查看insertNodeForAssetAtIndex:调用该方法的位置,您会发现它仅在视图被填充时发生,它被分配一个层或调用 setWantsLayer: 之前。

文档并没有说图层托管视图不能包含任何子视图,他们只是说您不能子视图添加到其中。在添加这些子视图的时间点,主视图尚未成为图层托管视图。通过为其分配手动创建的图层将其转换为图层托管视图后,不再添加子视图。

所以文档和这个特定的例子之间真的没有矛盾。话虽如此,进一步探索这一点可能会很有趣,也许从一开始就打开 QC 背景层,例如通过[self setUsesQuartzCompositionBackground:YES];在里面粘贴一个 right initWithFrame:

SPOLIER ALERT: 它似乎工作得很好。显示的创建有点慢(所有 QC 动画正在进行中并不奇怪),但除此之外它是一帆风顺的。

于 2012-05-23T13:05:13.607 回答
0

Apple 对这段代码的一条评论:它被破坏了。

首次启动应用程序时,请注意漂亮的渐变背景。打开 QC,然后关闭。

噗,没有渐变背景了。

于 2013-09-20T17:49:06.430 回答