我能在iPhone的Quartz 2D中进行旋转变换时移动原点吗?

8

如果这显而易见或者已经在其他地方讨论过,我很抱歉,但我已经搜索了一整天,还没有找到实际可行的解决方案。

我的问题如下:我目前正在全屏UIView中绘制一个图像。比如说,该图像位于UIView的右下角。我想在该图像的中心进行旋转变换(CGAffineTransformMakeRotation),但默认情况下,旋转命令会围绕UIView本身的中心旋转。结果,当我旋转时,我的图像在屏幕上移动,而不是停留在原地并围绕其自身中心旋转。

据我所知,我需要通过平移我的上下文,使原点(UIView的中心)位于我的图像的中心,然后旋转,并通过将其翻译回原始位置来恢复上下文。

以下是我得到的最接近可行方案,但问题在于,当图像旋转时,它会向下移动。我认为这是由于动画补间第一步翻译和第三步翻译之间的动画补间引起的,而不是意识到翻译的开始点和结束点将是相同的...

// Before this i'd make a call to a function that draws a path to a passed in context
CGAffineTransform inverseTranslation = CGAffineTransformMakeTranslation( transX, transY );
CGAffineTransform translation = CGAffineTransformMakeTranslation( -transX, -transY );
CGAffineTransform rot = CGAffineTransformMakeRotation( 3.14 );
CGAffineTransform final = CGAffineTransformConcat( CGAffineTransformConcat( inverseTranslation, rot ), translation );
// Then i apply the transformation animation like normal using self.transform = final etc etc

我也尝试了CGContextTranslateCTM和CGContextSaveGState/UIGraphicsPushContext等方法,但它们似乎没有什么效果。

我已经为此奋斗了几天,我的当前解决方案似乎很接近,但我不知道如何摆脱那个翻译缓动。有人有解决这个问题的方法或更好的方法吗?

[更新] 目前,我将图像绘制在UIView的中心,然后将UIView.center属性设置为我想要旋转的原点,然后执行旋转命令。看起来有点像黑客行为,但在我能够让真正的翻译工作之前,这是我的唯一选择。 谢谢!

4个回答

14

duncanwilcox的回答是正确的,但他忽略了一个部分,即您需要将视图层的锚点更改为要围绕旋转的点。

CGSize sz = theview.bounds.size;
// Anchorpoint coords are between 0.0 and 1.0
theview.layer.anchorPoint = CGPointMake(rotPoint.x/sz.width, rotPoint.y/sz.height);
[UIView beginAnimations:@"rotate" context:nil];
theview.transform = CGAffineTransformMakeRotation( 45. / 180. * M_PI );
[UIView commitAnimations];

这里有相关文档: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/Layers.html


2
快速评论- 编辑以显示在处理pi值时应使用math.h常量。 M_PI_4,M_PI_2,M_PI比所有舍入误差更好且更准确 :) - Eric G

8
这也是一种选择:简单的基础变换 ;-)
CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, angle);
transform = CGAffineTransformTranslate(transform,-x,-y);

其中(x,y)是您喜欢的旋转中心


2

旋转发生在视图层的锚点周围。默认的锚点是中心点(0.5, 0.5),因此仅进行旋转而没有平移应该就足够了。

我进行了一次快速测试,这对我起作用:

[UIView beginAnimations:@"rotate" context:nil];
self.transform = CGAffineTransformMakeRotation( 45. / 180. * 3.14 );
[UIView commitAnimations];

也许我的描述有点误导。我正在一个上下文中绘制某些东西(我称之为图像,但实际上只是使用上下文命令绘制的东西),它不在上下文的中心。我想要旋转,就好像上下文的中心在我的“图像”的中心一样。 - Skyler
快速评论- 编辑以显示在处理pi值时应使用math.h常量。 M_PI_4,M_PI_2,M_PI比所有舍入误差更好且更准确 :) - Eric G

1
如果你不想要动画效果,而只是设置新的旋转角度,你可以使用以下代码:
CGFloat newRotation = 3.14f 

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.0]; // no tweening
CGAffineTransform transform = CGAffineTransformMakeRotation(newRotation);
self.transform = transform;
[UIView commitAnimations];

旋转确实应该围绕UIView的中心进行。将animationDuration设置为零可以保证不会发生缓动。

但请确保您不要每秒执行60次此操作。使用这些工具创建类似游戏的动画非常诱人。这种类型的动画并不是针对基于帧的“大量精灵飞来飞去”的游戏而设计的。

对于这种情况 - 我已经走过那条路了 - 唯一的选择是OpenGL。


我确实想要旋转的动画,也许我可以使用您的0秒持续时间进行前后的转换,因为CGContextTranslateCTM似乎不起作用... - Skyler
在进行CGContextTranslateCTM之前,请确保您保存CGContext状态。然后恢复该状态。如果您只是在上下文中绘制后转换CTM,则它没有(明显的)效果。 - Kriem

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