如何改变CALayer动画的方向

Dig*_*ech 1 iphone animation core objective-c ios

如何改变CALayer动画的方向和起始位置?

例如,如果我使用以下代码为圆形设置动画:

-(void)drawCircle {
    CAShapeLayer *circleShapeLayer = [[CAShapeLayer alloc] init];
    circleShapeLayer.path          = [self circleBezierPath].CGPath;
    circleShapeLayer.strokeColor   = [UIColor lightGrayColor].CGColor;
    circleShapeLayer.fillColor     = [UIColor clearColor].CGColor;
    circleShapeLayer.lineWidth     = 2;
    [self.view.layer addSublayer:circleShapeLayer];

    CABasicAnimation *circleShapeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    circleShapeAnimation.timingFunction    = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    circleShapeAnimation.duration          = 1.0f;
    circleShapeAnimation.fromValue         = @(0.0f);
    circleShapeAnimation.toValue           = @(1.0f);
    [circleShapeLayer addAnimation:circleShapeAnimation forKey:@"strokeEnd"];
}

-(UIBezierPath *)circleBezierPath {
    UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 100, 100)];
    return circlePath;
}
Run Code Online (Sandbox Code Playgroud)

动画始终从3点开始,并以顺时针方向动画.

如何强制它从12点(或任何其他位置)开始并以逆时针方向制作动画?

Dav*_*ist 9

怎么了

当您在矩形中创建一个椭圆(使用CGPath函数的UIBezierPath时,它),它会创建一个适合指定矩形的椭圆或椭圆.这意味着椭圆的中心与矩形的原点不同:

矩形中的椭圆形

动画总是从3点钟开始逆时针旋转,因为这是一个弧形路径,它是默认坐标系中0到2π的圆圈:

角度在默认坐标系中

这意味着你动画笔画的路径看起来真的像这样:

在此输入图像描述

解决问题的错误方法

查看路径,您可以通过旋转视图来移动起点.不建议这样做,因为它有副作用.如果有任何子图层,那么它们也会被旋转.可以通过翻转视图(沿一个轴缩放负)或通过将笔划的开始从1设置为0而不是笔划的结束来改变笔划方向.

所有这些解决方案都可行,但有副作用,并且不太清楚什么是优选的.

更好的解决方案

我喜欢看这样的问题:动画代码正在做正确的事情,动画从无到有动画到所有动画,但路径的起点和行程方向不是预期的.这意味着"问题"在于路径.

而不是使用的bezierPathWithOvalInRect:,你可以使用任何起始角度去任何末端角沿顺时针或逆时针方向的圆弧创建自己的完整的圆.所需要的只是你计算圆的中心(以及起点和终点).查看默认坐标系,我们可以看到起始角度为3π/ 2或-π/ 2.然后,结束角度从起始角度加上或减去2π(取决于它是顺时针还是逆时针).

创建这样的弧可能看起来像这样:

- (UIBezierPath *)circleBezierPath
{
    CGRect boundingRect = CGRectMake(100, 100, 100, 100);
    CGPoint center      = CGPointMake(CGRectGetMidX(boundingRect), CGRectGetMidY(boundingRect));
    CGFloat radius      = MIN(CGRectGetWidth(boundingRect), CGRectGetHeight(boundingRect));

    CGFloat twelveOClockAngle = -M_PI_2;
    BOOL clockwise = NO; // NO for counter clockwise

    CGFloat startAngle = twelveOClockAngle;
    CGFloat endAngle = startAngle + (2.0*M_PI * (clockwise ? 1.0 : -1.0));

    return [UIBezierPath bezierPathWithArcCenter:center
                                          radius:radius
                                      startAngle:startAngle
                                        endAngle:endAngle
                                       clockwise:clockwise];
}
Run Code Online (Sandbox Code Playgroud)

  • 半径应该是宽度或高度 / 2 (2认同)