iOS CATransform3D 坐标

3
非常感谢您对此的帮助。我对视图应用了3D转换,并需要确定呈现视图的边缘坐标,以便可以在其旁边呈现另一个视图(没有任何像素间隔)。具体而言,我想要一系列视图(“页面”)像小册子一样折叠起来,通过动画效果改变角度。
    int dir = (isOddNumberedPage ? 1 : -1);
    float angle = 10.0;

    theView.frame = CGRectMake(pageNumber * 320, 0, 320, 460);        
    CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
    rotationAndPerspectiveTransform.m34 = -1.0 / 2000; // Perspective
    rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 
           dir * angle / (180.0 / M_PI), 0.0f, 1.0f, 0.0f);
    theView.layer.transform = rotationAndPerspectiveTransform;

    // Now need to get the top, left, width, height of the transformed view to correct the view's left offset

我尝试了多种方法,包括检查CALayer和使用一些找到的矩阵数学代码片段,但是我没有能够解决它,甚至无法接近(根据角度,相差20像素)。是否有一种方法可以在不花费两周时间阅读矩阵数学教科书的情况下完成这项任务?

1个回答

5
视图的框架是父视图坐标系中的轴对齐矩形。该框架完全包含视图的边界。如果视图被转换,框架会调整以紧密包围视图的新边界。
当您将Y轴旋转和透视应用于视图时,视图的左右边缘向其锚点移动(通常为视图的中心)。左边缘也会变得更高或更短,而右边缘则相反。
因此,视图的框架(应用变换后)将为您提供转换后视图的左边缘坐标和宽度,以及更高边缘的顶部和高度(可能是左侧或右侧边缘)。以下是我的测试代码:
NSLog(@"frame before tilting = %@", NSStringFromCGRect(self.tiltView.frame));
float angle = 30.0;
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = -1.0 / 2000; // Perspective
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 
       1 * angle / (180.0 / M_PI), 0.0f, 1.0f, 0.0f);
self.tiltView.layer.transform = rotationAndPerspectiveTransform;
NSLog(@"frame after tilting = %@", NSStringFromCGRect(self.tiltView.frame));

以下是输出结果:
2012-01-04 12:44:08.405 layer[72495:f803] frame before tilting = {{50, 50}, {220, 360}}
2012-01-04 12:44:08.406 layer[72495:f803] frame after tilting = {{62.0434, 44.91}, {190.67, 370.18}}

您还可以使用 convertPoint:fromView:convertPoint:toView: 方法,在父视图的坐标空间中获取视图的四个角的坐标。测试代码:

    CGRect bounds = self.tiltView.bounds;
    CGPoint upperLeft = bounds.origin;
    CGPoint upperRight = CGPointMake(CGRectGetMaxX(bounds), bounds.origin.y);
    CGPoint lowerLeft = CGPointMake(bounds.origin.x, CGRectGetMaxY(bounds));
    CGPoint lowerRight = CGPointMake(upperRight.x, lowerLeft.y);
#define LogPoint(P) NSLog(@"%s = %@ -> %@", #P, \
    NSStringFromCGPoint(P), \
    NSStringFromCGPoint([self.tiltView.superview convertPoint:P fromView:self.tiltView]))
    LogPoint(upperLeft);
    LogPoint(upperRight);
    LogPoint(lowerLeft);
    LogPoint(lowerRight);

输出:

2012-01-04 13:03:00.663 layer[72635:f803] upperLeft = {0, 0} -> {62.0434, 44.91}
2012-01-04 13:03:00.663 layer[72635:f803] upperRight = {220, 0} -> {252.713, 54.8175}
2012-01-04 13:03:00.663 layer[72635:f803] lowerLeft = {0, 360} -> {62.0434, 415.09}
2012-01-04 13:03:00.663 layer[72635:f803] lowerRight = {220, 360} -> {252.713, 405.182}

请注意,在父视图的坐标系中,上左角和上右角点的Y坐标不同。

谢谢Rob - 你真是个绝对的明星。在我的情况下,尝试了几次才让它工作,但是你的解释非常准确,所以我成功了。 - Phil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接