为啥使用 CATransform3D 进行这种转换会减小视图的宽度?

Posted

技术标签:

【中文标题】为啥使用 CATransform3D 进行这种转换会减小视图的宽度?【英文标题】:Why is this transformation using CATransform3D reducing the view's width?为什么使用 CATransform3D 进行这种转换会减小视图的宽度? 【发布时间】:2012-01-17 02:27:28 【问题描述】:

看看以下图像的进程:

这里发生的情况是,首先我选择了“棒球”,导致您看到的 3 个灰色视图向左旋转,以便具有各种级别的视图位于中间(第二张图片)。您可以看到此时视图的宽度已大大减小。第三张图片在点击包含运动名称的视图后出现,导致它旋转回中间。

据我所知,当视图旋转到中间时,它的宽度会减小。但我不知道为什么。

这是相关代码。 pos 是指有问题的view 的位置。 0表示在中间,1表示在中间右边一位,-1在中间左边一位,以此类推

- (void)perspectiveView:(MenuSection *)view forPosition:(NSInteger)pos


    CALayer *layer = view.layer;
    CATransform3D transform = CATransform3DIdentity;

    MenuSection *prevView = (pos >= 0) ? (MenuSection *)[self viewWithTag:view.tag - 1] : (MenuSection *)[self viewWithTag:view.tag + 1];

    if (pos == 0) 
        view.changingToFrame = CGRectMake(round((480 - view.frame.size.width)/2), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
        view.frame = view.changingToFrame;

     else 

        if (pos == 1) 
            NSLog(@"%@",NSStringFromCGRect(prevView.changingToFrame));
            view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x + prevView.frame.size.width + 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
            transform.m34 = 1.0 / 1000;
         else if (pos == -1)
            view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x - view.frame.size.width - 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
            transform.m34 = 1.0 / -1000;
         else if (pos == 2)
            view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x + prevView.frame.size.width + 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
            transform.m34 = 1.0 / 500;
         else if (pos == -2)
            view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x - view.frame.size.width - 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
            transform.m34 = 1.0 / -500;
        

        view.frame = view.changingToFrame;

        transform = CATransform3DRotate(transform, 45.0f * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
    

    layer.transform = transform;

【问题讨论】:

我通过添加非常少量的 z 轴变换解决了这个问题。它并不总是有效,如果做错了,会沿 y=x 轴折叠您的视图。 transform.m34 有什么用?我已经像这样旋转了视图,而宽度却没有改变。不知道发生了什么... 我从这篇文章中得到了转换代码:***.com/questions/347721/…。您能否提供一个代码示例来说明您如何旋转视图?如果我删除了 transform.m34 语句,那么我最终会得到如下所示的转换:cl.ly/2Z0v0P1U1T2a1p240x3L 【参考方案1】:

我已经解决了。事实证明,应用CATransform3D 实际上会改变视图的框架。在我发布的代码中,当我设置视图的新框架时(因为它旋转到不同的位置),我只是在CGRectMake() 中使用view.frame.size.width 来尝试保持宽度。但是,由于CATransform3D 之前修改了宽度,我没有得到我想要的实际宽度。

解决方案是将必要的UIViews 子类化并将其原始帧存储在 ivar 中。这样,在将视图移动到不同位置时,我总是可以将其用作参考点。

【讨论】:

【参考方案2】:

您不需要直接编辑 CATransform3D 矩阵(m34 等...)以使此效果起作用。试试这个:

if (pos == 0) 
     view.changingToFrame = CGRectMake(round((480 - view.frame.size.width)/2), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
    view.frame = view.changingToFrame;
 else 
    if (pos == 1) 
         view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x + prevView.frame.size.width + 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
        transform = CATransform3DRotate(transform, M_PI/4.0f, 0.0f, 1.0f, 0.0f);
     else if (pos == -1)
        view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x - view.frame.size.width - 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
        transform = CATransform3DRotate(transform, -M_PI/4.0f, 0.0f, 1.0f, 0.0f);
     else if (pos == 2)
        view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x + prevView.frame.size.width + 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
        transform = CATransform3DRotate(transform, M_PI/3.0f, 0.0f, 1.0f, 0.0f);
     else if (pos == -2)
        view.changingToFrame = CGRectMake(round(prevView.changingToFrame.origin.x - view.frame.size.width - 20), view.frame.origin.y, view.frame.size.width, view.frame.size.height);
        transform = CATransform3DRotate(transform, -M_PI/3.0f, 0.0f, 1.0f, 0.0f);
    
    view.frame = view.changingToFrame;

layer.transform = transform;

然后使用这些角度直到看起来正确为止。

【讨论】:

如果你想要透视,你必须直接修改m34。请参阅 Core Animation Programming Guide 中的“修改转换数据结构”。

以上是关于为啥使用 CATransform3D 进行这种转换会减小视图的宽度?的主要内容,如果未能解决你的问题,请参考以下文章

iOS:将屏幕坐标中的 CGPoint 转换为 iCarousel 中的 CATransform3D?

使用 CATransform3D 性能不佳

CATransform3D

CATransform3D UIView z 边框

iOS形变之CATransform3D

呈现模态视图控制器时,核心动画层表现得很奇怪。 CATransform3D 问题