iOS CATransform3D坐标

真的很感激这方面的任何帮助。 我在视图上应用了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像素输出)。 有没有一种方法可以做到这一点,而无需花费2周阅读矩阵数学教科书?

视图的框架是superview坐标系中的轴对齐矩形。 框架完全包围视图的边界。 如果视图已转换,则框架会调整以紧密包围视图的新边界。

将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: convertPoint:fromView:的坐标空间中获取视图角的坐标。 测试代码:

  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} 

请注意,superLeft坐标系中upperLeft和upperRight点的Y坐标不同。