CAKeyframeAnimation Manual Progress

2019-03-14 02:09发布

I have a UIView whose backing layer has a CAKeyframeAnimation with a simple straight line path set as its `path`.
Can I have the animation "frozen", so to speak, and manually change its progress?
For example: If the path is 100 points in length, setting the progress (offset?) to 0.45 should have the view move 45 points down the path.

I remember seeing an article that did something similar (moving a view along a path based on the value from a slider) via CAMediaTiming interfaces, but I haven't been able to find it, even after a few hours of searching. If I'm approaching this in a completely wrong way, please do let me know. Thanks.

Here's some sample code, if the above isn't clear enough.

- (void)setupAnimation
{

    CAKeyFrameAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:_label.layer.position];
    [path addLineToPoint:(CGPoint){200, 200}];

    animation.path = path.CGPath;

    animation.duration = 1;
    animation.autoreverses = NO;
    animation.removedOnCompletion = NO;
    animation.speed = 0;

    // _label is just a UILabel in a storyboard
    [_label.layer addAnimation:animation forKey:@"LabelPathAnimation"]; 
}

- (void)sliderDidSlide:(UISlider *)slider
{
    // move _label along _animation.path for a distance that corresponds to slider.value
}

2条回答
萌系小妹纸
2楼-- · 2019-03-14 02:49

This is based on what Jonathan said, only a bit more to the point. The animation is set up correctly, but the slider action method should be as follows:

- (void)sliderDidSlide:(UISlider *)slider 
{
    // Create and configure a new CAKeyframeAnimation instance
    CAKeyframeAnimation *animation = ...;
    animation.duration = 1.0;
    animation.speed = 0;
    animation.removedOnCompletion = NO;
    animation.timeOffset = slider.value;

    // Replace the current animation with a new one having the desired timeOffset
    [_label.layer addAnimation:animation forKey:@"LabelPathAnimation"];
}

This will make the label move along the animation's path based on timeOffset.

查看更多
狗以群分
3楼-- · 2019-03-14 02:49

Yes you can do this with the CAMediaTiming interface. You can set the speed of the layer to 0 and manualy set the timeOffset. Example of a simple pause/resume method:

- (void)pauseAnimation {
    CFTimeInterval pausedTime = [yourLayer convertTime:CACurrentMediaTime() fromLayer:nil];
    yourLayer.speed = 0.0;
    yourLayer.timeOffset = pausedTime;
}

- (void)resumeAnimation {

    CFTimeInterval pausedTime = [yourLaye timeOffset];
    if (pausedTime != 0) {
        yourLayer.speed = 1.0;
        yourLayer.timeOffset = 0.0;
        yourLayer.beginTime = 0.0;

        CFTimeInterval timeSincePause = [yourLayer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
        yourLayer.beginTime = timeSincePause;
    }
}
查看更多
登录 后发表回答