CABasicAnimation与CALayer路径一起使用时无法实现动画效果

20

我正在尝试将一个CALayer从正常的角落动画过渡到圆角。我只想将顶部角落变成圆角,所以我使用了UIBezierPath。以下是代码:

UIRectCorner corners = UIRectCornerTopLeft | UIRectCornerTopRight;

UIBezierPath* newPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(8.0f, 8.0f)];
UIBezierPath* oldPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(0.0f, 0.0f)];

CAShapeLayer* layer = [CAShapeLayer layer];
layer.frame = self.bounds;
layer.path = oldPath.CGPath;

self.layer.mask = layer;

CABasicAnimation* a = [CABasicAnimation animationWithKeyPath:@"path"];
[a setDuration:0.4f];
[a setFromValue:(id)layer.path];
[a setToValue:(id)newPath.CGPath];

layer.path = newPath.CGPath;
[layer addAnimation:a forKey:@"path"];

然而,当我运行这个程序时,角落会变圆,但没有动画效果——它瞬间发生。我在SO上看到了一些类似的问题,但它们没有解决我的问题。

iPhone CALayer 动画

为CALayer的shadowPath属性添加动画效果

我确信只是做错了一件小事就导致了这个问题,但是我无论如何也想不出来解决方法。

解决方案:

- (void)roundCornersAnimated:(BOOL)animated {
    UIRectCorner corners = UIRectCornerTopLeft | UIRectCornerTopRight;

    UIBezierPath* newPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(8.0f, 8.0f)];
    UIBezierPath* oldPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(0.0001f, 0.0001f)];

    CAShapeLayer* layer = [CAShapeLayer layer];
    layer.frame = self.bounds;

    self.layer.mask = layer;

    if(animated) {
        CABasicAnimation* a = [CABasicAnimation animationWithKeyPath:@"path"];
        [a setDuration:0.4f];
        [a setFromValue:(id)oldPath.CGPath];
        [a setToValue:(id)newPath.CGPath];

        layer.path = newPath.CGPath;
        [layer addAnimation:a forKey:@"path"];
    } else {
        layer.path = newPath.CGPath;
    }
}

实际上我需要做的就是为动画设置一个正确的“from”值。


1
解决方案作为答案而不是问题的一部分会更好,但这仍然很有帮助,所以+1 :) - buildsucceeded
3个回答

11

在我看来,您正在创建一个没有路径的形状图层,然后尝试动画添加路径。形状图层是特殊情况,不是这样工作的。

在动画之前和之后,您必须在形状图层中拥有路径,并且路径需要在两个时刻都具有相同数量的点。

您需要手动创建一个具有0个弧度圆角的圆角矩形路径(使用一系列的边和弧线),然后构建一个新的路径,其中要将所需圆角的半径设为非零,并将该路径安装为您的动画。

即使这样,也可能行不通,因为路径需要完全一致,而当半径为零时,我怀疑弧线会简化为点。

我刚刚找到了一个UIBezierPath调用,可以创建一个矩形,在其中可以选择要圆角的角落。该调用是bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:

那将创建一个带有任意数量的圆角的矩形。但是,我不确定它是否适用于路径动画。您可能需要请求所有角都被圆角化,而2个未圆角化的角设置为零半径。这样,您可能会得到与圆角矩形路径中具有相同点数的路径,以使路径动画正常工作。您需要尝试一下。


谢谢。你是对的。为动画设置正确的“from”值就解决了问题。 - eric.mitchell

5

尝试放置:

layer.path = newPath.CGPath;

之后:

[layer addAnimation:a forKey:@"path"];

0

从Andrew Wagner 这里 找到了一个非常优雅的解决方案。

本质上,系统将处理所有路径变化动画,你所需要做的就是:

  1. 实现一个CAShapeLayer子类
  2. 重写并实现actionForKey
  3. 像往常一样更新路径,你就能得到你想要的动画效果!

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