【问题标题】:CABasicAnimation for a CAShapeLayer disappears before it completes, and doesn't continue infinitelyCAShapeLayer 的 CABasicAnimation 在完成之前消失,并且不会无限继续
【发布时间】:2016-12-25 04:27:26
【问题描述】:

我正在尝试创建一个无限追踪的路径,该路径绘制并且它的背面消失了。但是,我的代码使路径在一次迭代后消失。事实上,层在路径的消失动画完成之前就消失了。相反,它似乎在绘图动画完成时消失了。

此外,一旦它消失,它不会再出现几秒钟(也许动画重复需要多长时间),然后再重新开始。

两个问题:

  1. 为什么在消失动画完成之前图层就消失了?

  2. 如何让动画连续播放而不消失?

提前感谢您!这是我的代码:

CGRect boundingFrame = CGRectMake(CGRectGetMidX(self.bounds) - 48.0, CGRectGetMidY(self.bounds) - 48.0, 96.0, 96.0);

_pathPoints = @[
                 [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(boundingFrame), CGRectGetMinY(boundingFrame) + squareSideWidth/2.0)],
                 [NSValue valueWithCGPoint:CGPointMake(CGRectGetMinX(boundingFrame) + squareSideWidth/2.0, CGRectGetMidY(boundingFrame))],
                 [NSValue valueWithCGPoint:CGPointMake(CGRectGetMidX(boundingFrame), CGRectGetMaxY(boundingFrame) - squareSideWidth/2.0)],
                 [NSValue valueWithCGPoint:CGPointMake(CGRectGetMaxX(boundingFrame) - squareSideWidth/2.0, CGRectGetMidY(boundingFrame))]
                ];

CAShapeLayer *line = [CAShapeLayer layer];
line.path = pathForPoints(_pathPoints).CGPath;
line.lineCap = kCALineCapRound;
line.strokeColor = color.CGColor;
line.fillColor = [UIColor clearColor].CGColor;
line.strokeEnd = 0.0;
[self.layer addSublayer:line];

NSMutableArray<CABasicAnimation *> *animations = [NSMutableArray new];
for (int i = 0; i < [_pathPoints count]; i++) {
    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.beginTime = index;
    drawAnimation.duration = 1.0;
    drawAnimation.fromValue = @(strokeEndForIndex(points, index - 1));
    drawAnimation.toValue = @(strokeEndForIndex(points, index));
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    drawAnimation.additive = YES;
    drawAnimation.removedOnCompletion = NO;

    CABasicAnimation *eraseAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
    eraseAnimation.beginTime = index + 0.75;
    eraseAnimation.duration = 1.0;
    eraseAnimation.fromValue = @(strokeEndForIndex(points, index - 1));
    eraseAnimation.toValue = @(strokeEndForIndex(points, index));
    eraseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    eraseAnimation.additive = YES;
    eraseAnimation.removedOnCompletion = NO;

    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.animations = @[drawAnimation, eraseAnimation];
    group.duration = 2.0 * [animations count];
    group.repeatCount = INFINITY;
    group.removedOnCompletion = NO;
    [line addAnimation:group forKey:@"line"];
}

辅助函数,供参考:

static CGFloat lengthOfPathWithPoints(NSArray<NSValue *> *points)
{
    CGFloat totalDist = 0;
    for (int i = 0; i < [points count]; i++) {
        CGFloat xDist = [points[i % [points count]] CGPointValue].x - [points[(i + 1) % [points count]] CGPointValue].x;
        CGFloat yDist = [points[i % [points count]] CGPointValue].y - [points[(i + 1) % [points count]] CGPointValue].y;
        totalDist += sqrt(pow(xDist, 2) + pow(yDist, 2));
    }
    return totalDist;
}

static CGFloat strokeEndForIndex(NSArray<NSValue *> *points, int index)
{
    // If it's the last index, just return 1 early
    if (index == [points count] - 1) {
        return 1.0;
    }
    // In the case where index = -1 (as it does for the initial erase animation fromValue), just return 0
    if (index < 0) {
        return 0.0;
    }

    CGFloat totalDist = 0;
    for (int i = 0; i < index + 1; i++) {
        CGFloat xDist = [points[i % [points count]] CGPointValue].x - [points[(i + 1) % [points count]] CGPointValue].x;
        CGFloat yDist = [points[i % [points count]] CGPointValue].y - [points[(i + 1) % [points count]] CGPointValue].y;
        totalDist += sqrt(pow(xDist, 2) + pow(yDist, 2));
    }

    return totalDist/lengthOfPathWithPoints(points);
}

static UIBezierPath *pathForPoints(NSArray<NSValue *> *points)
{
    UIBezierPath *path = [UIBezierPath new];
    [path moveToPoint:[[points firstObject] CGPointValue]];
    for (int i = 0; i < [points count]; i++) {
        [path addLineToPoint:[points[(i + 1) % 4] CGPointValue]];
    }
    return path;
}

【问题讨论】:

    标签: ios objective-c core-graphics core-animation calayer


    【解决方案1】:

    增加您的持续时间属性值并将您的 repeatCount = Float(Int.max) 更改为类似的内容。

    【讨论】:

    • 谢谢!试一试,没有任何运气。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-16
    • 1970-01-01
    相关资源
    最近更新 更多