在常见情况下,什么时候使用 Core Animation 而不是 UIView 动画是合适的
When is it appropriate to use Core Animation over UIView animation in common cases
这与许多小错误有关,这些小错误可能在刻板印象中被一个人认为是次要的,但另一个人却认为是主要的。
我越来越注意到的是,当使用所有风格 UIView animateWithDuration:
时,它实际上会不必要地修改一些东西,比如我的视图的多个属性,来做一个简单的 hide/reveal样式动画等..
事情似乎很挑剔,例如 UINavigationBar 没有为某个旋转过渡正确设置动画位置,或者 header 视图在帧更新时没有与状态栏一起动画,当视图当 parent 视图的属性发生变化时,子图层会隐式地设置不同的动画...
其中很多我一直在重新访问,并转换为 CAAnimations,因为它们似乎更易于管理,因为它们实际上并没有修改我的视图的目标 属性 值。
一个简单的例子是,使用 [view setHidden:]
,然后对其进行动画处理或在视图之外,但在动画运行时视图实际上已经可见或隐藏。
另一个是,需要 transform/rotate/scale UINavigationController 的视图,并使用 CAAnimation 来完成它,因为如果我修改 UINavigationController 的视图,UINavigationBar 不会移动到正确的位置,并且它的任何一个都是parent 视图的变换 属性 值。
所以在这个问题的结论中,我一直在来回,并且一直在寻找一个比另一个更适合我的情况的地方,但主要是,我想听听其他人对这些场景的看法,如果对 Apple 提供的内容有一些了解,我会对我的方法感觉更好。
提前致谢。
最终,所有UIKit风格的动画都转换为Core Animation风格的动画;也就是说,所有内容实际上都是使用 Core Animation 制作的。 API 之间的区别主要在于便利性:UIKit 样式的动画函数更新模型值,提交动画以反映表示层中随时间的变化。
您还必须小心,您正在为 UIKit 表示您可以设置动画的属性设置动画。例如,虽然您可以在技术上为 UIScrollView
上的属性设置动画,例如 contentSize
和 contentOffset
,但它们不受官方支持,因此您必须处理潜在的副作用。
此外,frame
是一个特例,因为它实际上是一个派生的属性,由center
、transform
和bounds
组成(在除了 CALayer
上的 anchorPoint
,UIView
不公开)。动画视图的 frame
可能会产生一大堆意想不到的问题,通常涉及旋转。 Core Animation 没有这个问题,因为 frame
不是 CALayer
上的显式动画 属性。如果您遇到涉及该视图的仿射变换(例如,缩放、平移、旋转)的奇怪行为,请尝试在 UIKit 风格的动画中使用 bounds
和 center
。
确实,在 UIKit 中对某些视图进行动画处理可能会产生意想不到的副作用或错误,因为除了对它们进行动画处理之外,您还要更新模型值。另一方面,Core Animation 更灵活一些,因为您可以细粒度地控制它更新模型层或表示层的方式和时间。
但我不同意 UIKit 进行不必要的修改。它修改需要修改的内容,以便提交您请求的动画更改以及更新其模型值。当您为 frame
等属性设置动画时,这将在当前 运行 循环之后在该视图上隐式调用 layoutSubviews()
,这可以级联到其他子视图等。
如果您希望 UIKit 在您设置动画之前执行其所有布局逻辑,请在调用动画块之前调用 setNeedsLayout()
和 layoutIfNeeded()
。如果您希望 UIKit 在提交动画的同时实际为整个子视图层次结构的更改设置动画,请指定 UIViewAnimationOptions.layoutSubviews
选项。这将在动画块内立即触发子视图布局,因此这些值也会被动画化。否则,动画更改的模型值将在下一个 运行 循环中触发布局更新。
一般来说,我很少注意到使用 UIKit 风格动画函数的问题。因此,作为在 iOS 上花费了大量时间制作动画的人,我会说:
尽可能使用 UIKit 风格的动画,因为它们真的很方便。当您 运行 遇到 UIKit 样式动画的问题,或者如果您需要对层的模型和表示值的更新方式进行特定控制时,应使用核心动画样式动画。
这与许多小错误有关,这些小错误可能在刻板印象中被一个人认为是次要的,但另一个人却认为是主要的。
我越来越注意到的是,当使用所有风格 UIView animateWithDuration:
时,它实际上会不必要地修改一些东西,比如我的视图的多个属性,来做一个简单的 hide/reveal样式动画等..
事情似乎很挑剔,例如 UINavigationBar 没有为某个旋转过渡正确设置动画位置,或者 header 视图在帧更新时没有与状态栏一起动画,当视图当 parent 视图的属性发生变化时,子图层会隐式地设置不同的动画...
其中很多我一直在重新访问,并转换为 CAAnimations,因为它们似乎更易于管理,因为它们实际上并没有修改我的视图的目标 属性 值。
一个简单的例子是,使用 [view setHidden:]
,然后对其进行动画处理或在视图之外,但在动画运行时视图实际上已经可见或隐藏。
另一个是,需要 transform/rotate/scale UINavigationController 的视图,并使用 CAAnimation 来完成它,因为如果我修改 UINavigationController 的视图,UINavigationBar 不会移动到正确的位置,并且它的任何一个都是parent 视图的变换 属性 值。
所以在这个问题的结论中,我一直在来回,并且一直在寻找一个比另一个更适合我的情况的地方,但主要是,我想听听其他人对这些场景的看法,如果对 Apple 提供的内容有一些了解,我会对我的方法感觉更好。
提前致谢。
最终,所有UIKit风格的动画都转换为Core Animation风格的动画;也就是说,所有内容实际上都是使用 Core Animation 制作的。 API 之间的区别主要在于便利性:UIKit 样式的动画函数更新模型值,提交动画以反映表示层中随时间的变化。
您还必须小心,您正在为 UIKit 表示您可以设置动画的属性设置动画。例如,虽然您可以在技术上为 UIScrollView
上的属性设置动画,例如 contentSize
和 contentOffset
,但它们不受官方支持,因此您必须处理潜在的副作用。
此外,frame
是一个特例,因为它实际上是一个派生的属性,由center
、transform
和bounds
组成(在除了 CALayer
上的 anchorPoint
,UIView
不公开)。动画视图的 frame
可能会产生一大堆意想不到的问题,通常涉及旋转。 Core Animation 没有这个问题,因为 frame
不是 CALayer
上的显式动画 属性。如果您遇到涉及该视图的仿射变换(例如,缩放、平移、旋转)的奇怪行为,请尝试在 UIKit 风格的动画中使用 bounds
和 center
。
确实,在 UIKit 中对某些视图进行动画处理可能会产生意想不到的副作用或错误,因为除了对它们进行动画处理之外,您还要更新模型值。另一方面,Core Animation 更灵活一些,因为您可以细粒度地控制它更新模型层或表示层的方式和时间。
但我不同意 UIKit 进行不必要的修改。它修改需要修改的内容,以便提交您请求的动画更改以及更新其模型值。当您为 frame
等属性设置动画时,这将在当前 运行 循环之后在该视图上隐式调用 layoutSubviews()
,这可以级联到其他子视图等。
如果您希望 UIKit 在您设置动画之前执行其所有布局逻辑,请在调用动画块之前调用 setNeedsLayout()
和 layoutIfNeeded()
。如果您希望 UIKit 在提交动画的同时实际为整个子视图层次结构的更改设置动画,请指定 UIViewAnimationOptions.layoutSubviews
选项。这将在动画块内立即触发子视图布局,因此这些值也会被动画化。否则,动画更改的模型值将在下一个 运行 循环中触发布局更新。
一般来说,我很少注意到使用 UIKit 风格动画函数的问题。因此,作为在 iOS 上花费了大量时间制作动画的人,我会说:
尽可能使用 UIKit 风格的动画,因为它们真的很方便。当您 运行 遇到 UIKit 样式动画的问题,或者如果您需要对层的模型和表示值的更新方式进行特定控制时,应使用核心动画样式动画。