7

レイヤーをホストする NSView (つまり、CALayer インスタンスを提供して で設定するsetLayer:NSView) には、明らかにサブビューを含めることができます。なぜ明らかに?Apple 独自のCocoa Slides サンプル コード プロジェクトAssetCollectionViewでは、レイヤーでサポートされている状態からレイヤーをホストしている状態に切り替えるチェックボックスをオンにできるためです。

- (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];たとえばinitWithFrame:.

SPOLIER ALERT: 問題なく動作しているようです。表示の作成は少し遅くなりますが (QC アニメーションが進行していることを考えれば驚くことではありません)、それ以外は順調です。

于 2012-05-23T13:05:13.607 に答える