CALayer展平子层

时间:2014-06-18 19:19:22

标签: ios objective-c core-animation calayer

我正在创建一个用户界面,我们有一副牌可以刷掉屏幕。

我希望能够做的是创建UIView的子类,它代表每张卡,然后修改transform属性以将它们移回(z轴)和稍微向上移动(y轴)以获得一副牌的样子。

阅读它我发现我需要使用CATransformLayer而不是普通的CALayer,以使z轴不会变平。我通过创建一个CATransformLayer来对此进行原型设计,我将其添加到CardDeckView的图层中,然后将所有卡添加到该CATransformLayer中。代码看起来有点像这样:

在init中:

// Initialize the CATransformSublayer
_rootTransformLayer = [self constructRootTransformLayer];
[self.layer addSublayer:_rootTransformLayer];

constructRootTransformLayer(角度方法是多余的,将会对牌组进行调整但后来决定不进行调整):

    CATransformLayer* transformLayer = [CATransformLayer layer];
transformLayer.frame = self.bounds;

// Angle the transform layer so we an see all of the cards
CATransform3D rootRotateTransform =  [self transformWithZRotation:0.0];
transformLayer.transform = rootRotateTransform;
return transformLayer;

然后添加卡片的代码如下:

// Set up a CardView as a wrapper for the contentView
RVCardView* cardView = [[RVCardView alloc] initWithContentView:contentView];

cardView.layer.cornerRadius = 6.0;
if (cardView != nil) {
    [_cardArray addObject:cardView];
    //[self addSubview:cardView];
    [_rootTransformLayer addSublayer:cardView.layer];
    [self setNeedsLayout];
}

请注意,我最初想要的是简单地将RVCardView直接添加为子视图 - 我想保留只添加图层不能执行的触摸事件。不幸的是,最终发生的事情如下:

Flattened Cards

如果我将卡片添加到rootTransformLayer,我最终会看到正确的外观:

enter image description here

请注意,我尝试在根视图(CardDeckView)上使用layerClass,如下所示:

+ (Class) layerClass
{
    return [CATransformLayer class];
}

我已经确认根层类型现在是CATransformLayer,但我仍然看到扁平的外观。为了防止扁平化,我还需要做些什么?

1 个答案:

答案 0 :(得分:4)

使用视图时,您会看到一个平面场景,因为没有设置透视图。要与OpenGL等3D图形进行比较,为了渲染场景,您必须设置摄像机矩阵,即将3D世界转换为2D图像的矩阵。 这是相同的:子图层内容在3D空间中使用CATransform3D进行转换,但是当父CALayer显示它们时,默认情况下会将它们投影到 x 上y 忽略 z 坐标。

请参阅Apple文档中的Adding Perspective to Your Animations。这是您缺少的代码:

CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0 / eyePosition; // ...on the z axis

myParentDeckView.layer.sublayerTransform = perspective;

请注意,为此,您不需要使用CATransformLayer,只需简单的CALayer即可:

CALayer can handle 3D projections

这是应用于图片中的子视图的转换(eyePosition = -0.1):

// (from ViewController-viewDidLoad)
for (UIView *v in self.view.subviews) {
    CGFloat dz = (float)(arc4random() % self.view.subviews.count);
    CATransform3D t = CATransform3DRotate(CATransform3DMakeTranslation(0.f, 0.f, dz),
                                          0.02,
                                          1.0, 0.0, 0.0);
    v.layer.transform = t;
}

this question中指出了使用CATransformLayer的原因。 CALayer" rasterizes"它的变换子层然后应用它自己的变换,而CATransformLayer保留完整的层次结构并独立绘制每个子层;仅当您有多个 3D转换的子层级别时才有用。在您的情况下,场景树只有一个级别:卡座视图(它本身具有转换的单位矩阵)和卡片视图,子视图(而是在3D空间中移动)。因此CATransformLayer在这种情况下是多余的。