如何旋转任意点周围的对象?

我想旋转一个UILabel在一个圆形的任意点,而不是一条直线。 这是我的代码。最后一点是完美的,但它在初始点和结束点之间是一条直线。

- (void)rotateText:(UILabel *)label duration:(NSTimeInterval)duration degrees:(CGFloat)degrees { /* Setup the animation */ [UILabel beginAnimations:nil context:NULL]; [UILabel setAnimationDuration:duration]; CGPoint rotationPoint = CGPointMake(160, 236); CGPoint transportPoint = CGPointMake(rotationPoint.x - label.center.x, rotationPoint.y - label.center.y); CGAffineTransform t1 = CGAffineTransformTranslate(label.transform, transportPoint.x, -transportPoint.y); CGAffineTransform t2 = CGAffineTransformRotate(label.transform,DEGREES_TO_RADIANS(degrees)); CGAffineTransform t3 = CGAffineTransformTranslate(label.transform, -transportPoint.x, +transportPoint.y); CGAffineTransform t4 = CGAffineTransformConcat(CGAffineTransformConcat(t1, t2), t3); label.transform = t4; /* Commit the changes */ [UILabel commitAnimations]; } 

你应该设置你自己的anchorPoint

使用关键帧animation实际上是改变了定位点的过度杀伤力。

锚点是所有变换应用的点,默认锚点是中心。 通过将定位点移动到(0,0),您可以改为使图层从最底angular开始旋转。 通过将锚点设置为xy超出范围0.0 – 1.0的某个值,可以使图层围绕位于其边界之外的点进行旋转。

请阅读核心animation编程指南中关于图层几何和变换的章节了解更多信息。 它详细地通过图像来帮助你理解。


编辑:有一点要记住

使用位置,边界和定位点来计算图层的框架(也是视图的框架)。 改变anchorPoint将改变你的视图出现在屏幕上的位置。 你可以通过在改变定位点之后重新设置框架来解决这个问题(这会为你设置位置)。 否则,您可以将位置设置为您正在旋转的位置。 文档(链接到上面)也提到了这一点。


适用于你的代码

应该更新您称为“transportPoint”的点,以计算旋转点与标签左下angular之间的差值除以宽度和高度。

 // Pseudocode for the correct anchor point transportPoint = ( (rotationX - labelMinX)/labelWidth, (rotationX - labelMinY)/labelHeight ) 

我也把轮换点作为你方法的一个参数。 完整的更新代码如下:

 #define DEGREES_TO_RADIANS(angle) (angle/180.0*M_PI) - (void)rotateText:(UILabel *)label aroundPoint:(CGPoint)rotationPoint duration:(NSTimeInterval)duration degrees:(CGFloat)degrees { /* Setup the animation */ [UILabel beginAnimations:nil context:NULL]; [UILabel setAnimationDuration:duration]; // The anchor point is expressed in the unit coordinate // system ((0,0) to (1,1)) of the label. Therefore the // x and y difference must be divided by the width and // height of the label (divide x difference by width and // y difference by height). CGPoint transportPoint = CGPointMake((rotationPoint.x - CGRectGetMinX(label.frame))/CGRectGetWidth(label.bounds), (rotationPoint.y - CGRectGetMinY(label.frame))/CGRectGetHeight(label.bounds)); [label.layer setAnchorPoint:transportPoint]; [label.layer setPosition:rotationPoint]; // change the position here to keep the frame [label.layer setTransform:CATransform3DMakeRotation(DEGREES_TO_RADIANS(degrees), 0, 0, 1)]; /* Commit the changes */ [UILabel commitAnimations]; } 

我决定发布我的解决scheme作为答案。 它工作正常接受它没有旧的解决scheme的曲线animation(UIViewAnimationCurveEaseOut),但我可以整理出来。

 #define DEGREES_TO_RADIANS(angle) (angle / 180.0 * M_PI) - (void)rotateText:(UILabel *)label duration:(NSTimeInterval)duration degrees:(CGFloat)degrees { CGMutablePathRef path = CGPathCreateMutable(); CGPathAddArc(path,nil, 160, 236, 100, DEGREES_TO_RADIANS(0), DEGREES_TO_RADIANS(degrees), YES); CAKeyframeAnimation *theAnimation; // animation object for the key path theAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; theAnimation.path=path; CGPathRelease(path); // set the animation properties theAnimation.duration=duration; theAnimation.removedOnCompletion = NO; theAnimation.autoreverses = NO; theAnimation.rotationMode = kCAAnimationRotateAutoReverse; theAnimation.fillMode = kCAFillModeForwards; [label.layer addAnimation:theAnimation forKey:@"position"]; } 

CAKeyframeAnimation是这项工作的正确工具。 大多数UIKitanimation是在开始点和结束点之间。 中点不考虑。 CAKeyframeAnimation允许您定义这些中间点以提供非线性animation。 你将不得不为你的animation提供合适的bezierpath。 你应该看看this example和Apple文档中提供的this example ,看看它是如何工作的。

翻译,围绕中心旋转,翻译回来。