当前位置: 首页 > 知识库问答 >
问题:

UIView animateKeyframesWithDuration与标准动画块动画不同

丌官哲彦
2023-03-14

我最近发现了一些UIView动画代码,并注意到它没有正确使用animateKeyframesWithDuration:delay:options:animations:completion:方法,并且一直在尝试修复它,但由于某些原因,动画不完全相同。

以下是我找到的代码:

view.transform = CGAffineTransformMakeTranslation(300, 0);

[UIView animateKeyframesWithDuration:duration/4 delay:delay options:0 animations:^{
    // End
    view.transform = CGAffineTransformMakeTranslation(-10, 0);
} completion:^(BOOL finished) {
    [UIView animateKeyframesWithDuration:duration/4 delay:0 options:0 animations:^{
        // End
        view.transform = CGAffineTransformMakeTranslation(5, 0);
    } completion:^(BOOL finished) {
        [UIView animateKeyframesWithDuration:duration/4 delay:0 options:0 animations:^{
            // End
            view.transform = CGAffineTransformMakeTranslation(-2, 0);
        } completion:^(BOOL finished) {
            [UIView animateKeyframesWithDuration:duration/4 delay:0 options:0 animations:^{
                // End
                view.transform = CGAffineTransformMakeTranslation(0, 0);
            } completion:^(BOOL finished) {
            }];
        }];
    }];
}];

这有两个问题:

  1. 应该真正使用关键帧动画,而不是在完成块中嵌套动画
  2. 使用animateKeyframesWithDuration:delay:options:animations:completion:。如果不调用此方法,则此方法的行为将类似于标准UIView动画块

请参阅此处有关此方法的苹果文档。

因此,我试图通过正确使用该方法来解决此问题:

view.transform = CGAffineTransformMakeTranslation(300, 0);
double frameDuration = 1.0/4.0; // 4 = number of keyframes

[UIView animateKeyframesWithDuration:duration delay:delay options:0 animations:^{
    [UIView addKeyframeWithRelativeStartTime:0*frameDuration relativeDuration:frameDuration animations:^{
        view.transform = CGAffineTransformMakeTranslation(-10, 0);
    }];
    [UIView addKeyframeWithRelativeStartTime:1*frameDuration relativeDuration:frameDuration animations:^{
        view.transform = CGAffineTransformMakeTranslation(5, 0);
    }];
    [UIView addKeyframeWithRelativeStartTime:2*frameDuration relativeDuration:frameDuration animations:^{
        view.transform = CGAffineTransformMakeTranslation(-2, 0);
    }];
    [UIView addKeyframeWithRelativeStartTime:3*frameDuration relativeDuration:frameDuration animations:^{
        view.transform = CGAffineTransformMakeTranslation(0, 0);
    }];
} completion:nil];

我觉得两个动画应该是相同的,但是它们不是。我在尝试中做错了什么?

编辑:示例项目(使用命令T在模拟器中切换慢速动画)

共有1个答案

华森
2023-03-14

tl;dr:它们看起来可能不同,因为它们做的事情不同,并且会在两个视图中添加不同的动画。不幸的是,我真的不知道如何修复它。

正如您已经说过的,第一个版本没有正确使用API。它不会使用addKeyframeWithRelativeStartTime:relativeDuration:animations添加关键帧,而是直接在动画块内更改属性。然后在完成块中创建一个新的“关键帧动画”(您很快就会明白为什么我在那里使用了短引号)。

在幕后,这实际上不会产生关键帧动画(CAKeyframeAnimations)(尽管我认为你不应该依赖这个事实)。这是我在项目中添加到视图1后面的层的四个动画对象中所做的一些日志记录。(我作弊了一点,只记录了变换的.m41部分(对应于沿x的变换))。

BASIC
keyPath: transform
duration: 0.125
from: 300.0
model value: -10.0
timing: easeInEaseOut

BASIC
keyPath: transform
duration: 0.125
from: -10.0
model value: 5.0
timing: easeInEaseOut

BASIC
keyPath: transform
duration: 0.125
from: 5.0
model value: -2.0
timing: easeInEaseOut

BASIC
keyPath: transform
duration: 0.125
from: -2.0
model value: 0.0
timing: easeInEaseOut

正如您所看到的,每个动画都有一个fromValue,但既没有toValue,也没有byValue。正如您在文档中所看到的,这意味着:

fromValuenil。在fromValue和属性的当前表示值之间进行插值。

另一方面,将关键帧正确添加到动画中的第二个版本会导致将这个单独的CAKeyframeAnimation添加到view2后面的层中。(我仍然只记录了. m41转换的一部分)

KEYFRAME 
keyPath: transform
duration: 0.500
values: (
    300,
    -10,
    5,
    -2,
    0
)
keyTimes: (
    0.0,
    0.25,
    0.5,
    0.75,
    1.0
)
timing: easeInEaseOut
timings: (nil)
calculationMode: linear

正如您所看到的,它在相同的值之间以相同的时间设置动画,但在单个关键帧动画中。它还具有相同的总持续时间,并使用相同的计时功能。

有一件事我不明白。如果我修改真正的关键帧动画(在我重写的addAnimation: forKey:调用Super之前)以显式设置定时函数数组中的定时函数,那么它们看起来确实完全一样。也就是说,我在关键帧动画添加到图层之前对其执行此操作。

CAMediaTimingFunction *function = keyFrame.timingFunction;
keyFrame.timingFunction = nil;
keyFrame.timingFunctions = @[function, function, function, function]; 

这个技巧非常难看,除了纯粹的调试,你永远不应该使用它!

嗯,我想答案与UIKit在第二种情况下创建的关键帧动画的时间函数数组有关。这几乎是我得到的唯一结论。

也就是说,我不知道这是否是一个bug,也不知道如何修复它。我只知道您项目中的代码在核心动画级别上的实际作用。

 类似资料:
  • 动画剪辑 动画剪辑是 Unity 动画系统的核心元素。Unity 不仅支持从外部源导入动画,而且支持在编辑器的动画视图中创建和编辑动画(剪辑)。 从外部源导入动画 从外部源导入的动画剪辑可能包括: 动作捕捉工作室捕捉的人形动画 设计师通过外部 3D 程序(例如 3D Max 或 Maya)创建的动画 第三方的动画集合库(例如来自 Unity Asset store) 导入的单个时间线等分切割为多个

  • 【动画模块性能】页面主要展示项目运行过程中动画模块的CPU占用情况,主要包括以下几个部分: 数据汇总 该项主要展示项目运行过程中的 “动画片段数量峰值”、“Animator.Update CPU均值”、“Animation.Update CPU均值” 和 “蒙皮网格更新CPU均值”。 注意: Animation.Update 对应的是Unity 3.x 动画系统,Animator.Update 对

  • 在实际开发中,3D美术提供的三维模型可能包含帧动画数据需要你解析渲染,比如一个机械的装配过程,一个车门开关的动作,一个物体的移动动画。这时候你首先要对建立帧动画的概念,然后对Threejs帧动画相关的API使用规则进行熟悉,这样才能很好的解析加载的外部模型包含的帧动画。

  • 我有一个动画块来执行一个简单的基于变换的动画,在完成时从它的超级视图中删除有问题的视图。 然后我使用Tech Q详述的代码 但是,此代码不会阻止完成代码的执行。因此,为了防止代码执行,我将完成代码更改为: 当检查finished==TRUE时,动画块暂停时,将阻止执行完成代码。如果在“取消暂停”动画之前超过持续时间,则不会执行完成代码。即在本例中,msgView仍保留在superview中。 是否

  • 动画控制器 动画控制器允许你为一个角色或其他游戏对象安排和维护一组动画。 控制器引用了动画剪辑,并且使用 状态机 来管理各种动画状态和它们之间的转换,可以把状态机认为是一种流程图,或者是一段在 Unity 中用可视化编程语言编写的简单程序。 下面的章节涵盖了 动画系统 Mecanim 提供的控制和序列化动画的主要功能。

  • UIView animateWithDuration的文档称,在动画期间,所有用户交互都被阻止。但我想知道它是否也会在预动画延迟期间阻塞。 文件上说 “在动画制作过程中,将暂时禁用正在制作动画的视图的用户交互。(在iOS 5之前,将禁用整个应用程序的用户交互。)如果希望用户能够与视图交互,请在选项参数中包含UIViewAnimationOptionAllowUserInteraction常量。"