核心动画围绕点旋转

4

我希望将IBOutlet围绕父视图中的特定点旋转,目前我只知道如何围绕锚点旋转它,但是我想使用对象层外的点。

旋转角度相对于该点从设备方向计算而来。

- (void)viewDidLoad{
[super viewDidLoad];
locationManager=[[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.headingFilter = 1;
locationManager.delegate=self;
[locationManager startUpdatingHeading];
[locationManager startUpdatingLocation];
compassImage.layer.anchorPoint=CGPointZero;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
    // Convert Degree to Radian and move the needle
    float oldRad =  -manager.heading.trueHeading * M_PI / 180.0f;
    float newRad =  -newHeading.trueHeading * M_PI / 180.0f;        
    CABasicAnimation *theAnimation;
    theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    theAnimation.fromValue = [NSNumber numberWithFloat:oldRad];
    theAnimation.toValue=[NSNumber numberWithFloat:newRad];
    theAnimation.duration = 0.5f;
    [compassImage.layer addAnimation:theAnimation forKey:@"animateMyRotation"];
    compassImage.transform = CGAffineTransformMakeRotation(newRad);

    NSLog(@"%f (%f) => %f (%f)", manager.heading.trueHeading, oldRad, newHeading.trueHeading, newRad);

  }

如何使UIImageView绕(x,y)旋转alpha度?

对于旋转,您可以更改视图层的锚点就像我在这里所做的那样 - David Rönnqvist
优秀的例子,为什么不把它作为答案呢? - user3157423
主要是因为时间不够。我不想发一个“只有链接”的答案,但我也没有什么反对在评论中发一个链接的意见。 - David Rönnqvist
2
不要忘记设置你的CAShapeLayer的边界。 - Fattie
@Fattie 不能点赞两次。这就是你可能在第一时间错过的东西。然后设置一个位置... - Dima Deplov
2个回答

18

要围绕特定点(内部或外部)旋转,您可以更改图层的锚点,然后应用常规旋转变换动画,类似于我在此博客文章中所写的内容

您只需要注意,锚点还会影响图层出现在屏幕上的位置。当您更改锚点时,还必须更改位置以使图层出现在屏幕上的相同位置。

假设该图层已经放置在其起始位置,并且要旋转的点已知,则可以像这样计算锚点和位置(请注意,锚点位于图层边界的单位坐标空间中(这意味着x和y在边界内从0到1范围内)):

CGPoint rotationPoint = // The point we are rotating around

CGFloat minX   = CGRectGetMinX(view.frame);
CGFloat minY   = CGRectGetMinY(view.frame);
CGFloat width  = CGRectGetWidth(view.frame);
CGFloat height = CGRectGetHeight(view.frame);

CGPoint anchorPoint =  CGPointMake((rotationPoint.x-minX)/width,
                                   (rotationPoint.y-minY)/height);

view.layer.anchorPoint = anchorPoint;
view.layer.position = rotationPoint; 

然后,您只需对其应用旋转动画,例如:

CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotate.toValue = @(-M_PI_2); // The angle we are rotating to
rotate.duration = 1.0;

[view.layer addAnimation:rotate forKey:@"myRotationAnimation"];

请注意您已更改了锚点,因此position不再位于frame的中心位置,如果您应用其他变换(例如缩放),它们也将相对于锚点进行。


动画结束后如何将新位置应用于视图的框架? - Bhargav Soni
@BhargavSoni 如果您同时指定了 toValuefromValue,那么在将动画添加到属性之前将其设置为最终值就足以在动画结束后获得新值。 - David Rönnqvist
谢谢。这对我非常有效。我不得不将它转换为Swift,下面是我粘贴的内容,以节省其他人的时间,但概念似乎很坚实。此外,在我的情况下,我正在旋转和动画化BezierPath,因此我必须通过旋转点偏移路径坐标,但它起作用了。 - Trevis Thomas
@TrevisThomas 如果您想围绕形状的中心旋转,您应该能够使用相同的代码并给CAShapeLayer一个bounds(可能是路径的boundingBoxOfPath)。默认情况下,形状层将没有大小(0宽度和高度),但在其自身边界之外绘制。这有效地使它看起来像它的“中心”是左上角。 - David Rönnqvist
1
@MikalaiDaronin 感谢您注意到这一点。它有一个意外的尾随斜杠,现在已经修复了。 - David Rönnqvist
显示剩余2条评论

3

将David的答案翻译为Swift 3:

    let rotationPoint = CGPoint(x: layer.frame.width / 2.0, y: layer.frame.height / 2.0) // The point we are rotating around

    print(rotationPoint.debugDescription)
    let width = layer.frame.width
    let height = layer.frame.height
    let minX = layer.frame.minX
    let minY = layer.frame.minY

    let anchorPoint = CGPoint(x: (rotationPoint.x-minX)/width,
                              y: (rotationPoint.y-minY)/height)

    layer.anchorPoint = anchorPoint;
    layer.position = rotationPoint;

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