使用 [UIView animateKeyframesWithDuration] 为 UIView 设置动画的奇怪行为

Posted

技术标签:

【中文标题】使用 [UIView animateKeyframesWithDuration] 为 UIView 设置动画的奇怪行为【英文标题】:Strange behavior animating a UIView using [UIView animateKeyframesWithDuration] 【发布时间】:2014-08-28 15:39:59 【问题描述】:

我正在尝试创建一种效果,其中三个箭头交替地从可见变为不可见。

我做了一个简单的算法,每个箭头都从不同的 alpha 值开始(如果有 3 个箭头,第一个将从 alpha=1 开始,第二个从 alpha=0.6667 开始,第三个从 alpha=0.3337 )。然后我开始一个关键帧动画:

将箭头不透明度从当前的 alpha 更改为 0(计算持续时间) 立即将箭头不透明度设置为 1 将箭头不透明度从 1 更改为第一个值集

但似乎由于某种原因跳过了某些步骤。

一个简单的例子:

[UIView animateKeyframesWithDuration:2 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewKeyframeAnimationOptionRepeat animations:^

    [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0 animations:^
        _animatedView.alpha = 0.5;
    ];

    [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^
        _animatedView.alpha = 0;
    ];

    [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0 animations:^
        _animatedView.alpha = 1;
    ];

    [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^
        _animatedView.alpha = 0.5;
    ];

 completion:nil];

在这种情况下,它应该立即到 0.5,在 1 秒内从 0.5 到 0,在 1 秒内立即到 1,从 1 到 0.5。因此,它应该进行无缝过渡,看起来视图正在出现和消失,但看起来动画在 alpha=0.5 上停留了一段时间。

理论上,效果应该和使用这个关键帧动画一样:

[UIView animateKeyframesWithDuration:2 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewKeyframeAnimationOptionRepeat animations:^
    [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0 animations:^
        _animatedView.alpha = 1;
    ];
    [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1 animations:^
        _animatedView.alpha = 0;
    ];
 completion:nil];

【问题讨论】:

您尝试做的类似于使用具有相对动画开始和持续时间偏移的动画组。我以前也尝试过这样做。尝试在形状层内的 4 条不同路径之间设置无缝过渡的动画。我的经验是它们由于某种原因无法正常工作(我尝试了很多)。因此,我为图层编写了自己的完成块逻辑,并在其中完成另一个动画后触发了一个动画。代码看起来有点愚蠢,但动画就像一个魅力:)。所以也许你可以尝试同样的方法。 【参考方案1】:

如果您想以相同的方式为 N 个视图设置动画:

CGFloat count = [self.animatedViews count];
CGFloat period = 1.0f / count;

__weak NSArray *weakViews = self.animatedViews;

[UIView animateKeyframesWithDuration:2.0f delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear | UIViewKeyframeAnimationOptionRepeat animations:^

    for (NSUInteger index = 0; index < count; ++index) 
        UIView *animatedView = weakViews[index];

        CGFloat startDelay = period * index;

        [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0 animations:^
            animatedView.alpha = startDelay;
        ];

        [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:startDelay animations:^
            animatedView.alpha = 0.0f;
        ];

        [UIView addKeyframeWithRelativeStartTime:startDelay relativeDuration:0.0f animations:^
            animatedView.alpha = 1.0f;
        ];

        [UIView addKeyframeWithRelativeStartTime:startDelay relativeDuration:(1.0f - startDelay) animations:^
            animatedView.alpha = startDelay;
        ];
    
 completion:nil];

【讨论】:

这是我所做的确切实现,但由于某种原因无法正常工作。第一个箭头可以正常工作,其他箭头则不能。虽然所有箭头上的效果看起来都还不错,但如果您查看每个箭头,您会发现有些箭头没有从 1 到 0 进行无缝 alpha 转换。 所以所有箭头的动画(除了第一个)不够无缝?这是唯一的问题吗? 是的,如果您仔细观察,有些观看次数永远不会达到 0,并且会在开始 alpha 上停留一段时间。 问题可能在于计算周期(CGFloat period = 1.0f / count;),其中分子应始终为 1。它与持续时间不同。 在我发送答案之前,我检查了模拟器上的代码。并且没有像“某些视图永远不会达到 0”这样的东西。请确保一切都一样。

以上是关于使用 [UIView animateKeyframesWithDuration] 为 UIView 设置动画的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

UIView.animateKeyframes 跳转到下一个动画的开始而不是平滑过渡

UIView animateKeyframes 不起作用

如何消除 animateKeyframes 动画开始和结束的延迟 - Swift UIKit

如何根据后者的进度为已经运行的动画添加动画?

子类化 UIView 或使用 UIView 组合

如何在 iOS 中使用 UIView 动画显示 UIView,如 UIAction 表?