如何围绕任意点旋转对象?

问题描述

| 我想以圆形而不是直线的方式围绕任意点旋转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
使用关键帧动画来真正改变锚点是非常过头的。 锚点是从其应用所有变换的点,默认锚点是中心。通过将锚点移动到(0,0),您可以改为使图层从最底角旋转。通过将锚点设置为x或y超出0.0-1.0的范围,可以使图层绕其边界之外的点旋转。 有关更多信息,请阅读《 Core Animation编程指南》中有关“图层几何和变换”的部分。它会通过图像进行详细介绍,以帮助您理解。 编辑:要记住的一件事 图层的框架(也是视图的框架)是使用位置,边界和锚点计算的。更改anchorPoint将更改视图在屏幕上的显示位置。您可以通过更改锚点后重新设置框架来解决此问题(这将为您设置位置)。否则,您可以将位置设置为旋转到自己的位置。文档(链接到上面)也提到了这一点。 应用于您的代码 应该更新称为““ transportPoint \”的点,以计算旋转点和标签左下角之间的差除以宽度和高度。
// 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),1)];   

    /* Commit the changes */
    [UILabel commitAnimations];
}
    ,        我决定发布我的解决方案作为答案。如果没有旧解决方案的曲线动画(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
是完成此工作的正确工具。大多数UIKit动画都在起点和终点之间。不考虑中间点。 CAKeyframeAnimation允许您定义那些中间点以提供非线性动画。您将必须为动画提供适当的贝塞尔曲线路径。您应查看ѭ6和Apple文档中提供的内容,以了解其工作原理。     ,        平移,绕中心旋转,向后平移。     

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...