ios - CALayer 扁平子层

标签 ios objective-c core-animation calayer

我正在创建一个 UI,其中有一副纸牌,您可以将其滑出屏幕。

我希望能够做的是创建一个 UIView 的子类来表示每张卡片,然后修改 transform 属性以将它们向后移动(z 轴)并稍微向上移动(y 轴)以获得一副纸牌的外观。

阅读它后,我发现我需要使用 CATransformLayer 而不是普通的 CALayer,以免 z 轴变平。我通过创建一个 CATransformLayer 将其添加到 CardDeckView 的层,然后将我的所有卡片添加到该 CATransformLayer 来制作原型(prototype)。代码看起来有点像这样:

在初始化中:

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

constructRootTransformLayer(angle 方法是多余的,本来打算对甲板倾斜但后来决定不这样做):

    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 直接添加为 subview - 我想保留触摸事件,而仅添加层不会这样做。不幸的是,最终发生的事情如下:

Flattened Cards

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

enter image description here

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

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

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

最佳答案

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

参见 Adding Perspective to Your Animations在 Apple 文档上。这是您缺少的代码:

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

myParentDeckView.layer.sublayerTransform = perspective;

请注意,为此,您不需要使用 CATransformLayer,一个简单的 CALayer 就足够了:

CALayer can handle 3D projections

这里是应用于图片中的 subview 的变换(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“栅格化”其转换后的子层,然后应用自己的转换,而 CATransformLayer 保留完整的层次结构并独立绘制每个子层;仅当您有超过一层的 3D 转换 子层时,它才有用。在您的情况下,场景树只有一个级别:甲板 View (它本身具有单位矩阵作为转换)和卡片 View , subview (而是在 3D 空间中移动)。所以 CATransformLayer 在这种情况下是多余的。

关于ios - CALayer 扁平子层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24293477/

相关文章:

ios - Dealloc 被调用但实时内存没有减少

ios - iOS-脏内存持续增长

iphone - 将模型层基于 NSManagedObject 的负面后果是什么(如果有的话)?

iphone - Core Graphics 文本比 Core Text 快得多——我觉得我错过了什么

ios - 如何在持续时间内为一条线设置动画?

iphone - 如何将图像数据和网站URL一起发布在我的Facebook墙上

ios - 从 WKWebview 从 cordova-ios 的数据目录加载 html 文件

java - java中如何将苹果新HEIC格式的图片转为jpg?

ios - 当主视图缩小时, subview 无法正确设置动画

ios - 使用 UIImageViews 和框架或 CALayers 或其他东西?