返回文章列表

SwiftUI 系列 09|动画入门:什么时候该用 animation,什么时候该用 withAnimation

真正要分清的不是 API 名字,而是动画是附着在状态变化上,还是你要对一次具体变化显式包裹

SwiftUI 动画最容易给人一种“好像很简单”的感觉:

  • 加个 .animation
  • 或者包个 withAnimation

页面就动起来了。

但真实项目里,动画最容易出问题的地方恰恰就在这里:

  • 为什么这里也跟着动了
  • 为什么不该动的地方动了
  • 为什么某次状态变化没有动画
  • 为什么列表刷新时动画特别怪

这说明很多时候我们不是不会写动画,而是没有先搞清:

这次动画到底是应该附着在某种状态变化上,还是应该只包裹某一次具体的变化过程。

一、SwiftUI 动画的核心不是“让 view 动”,而是“让状态变化被插值呈现”

这点特别重要。

如果还是用 UIKit 思路去理解动画,很容易默认:

  • 我要让某个控件动起来

而 SwiftUI 更像是在做:

  • 当状态从 A 变成 B 时,用动画把这个变化过程表达出来

这意味着动画天然依附于状态变化。
所以真正要判断的不是“动不动”,而是:

  • 哪个状态变化值得被动画化
  • 动画作用范围应该多大

二、.animationwithAnimation 的差别,不只是写法不同,而是控制粒度不同

一个更实用的理解是:

  • .animation 更像给某类状态变化附加动画倾向
  • withAnimation 更像对某一次明确的状态修改做显式包裹

所以当你用 .animation 时,更像是在说:

这块视图对于某些状态变化,应该默认有动画反应。

withAnimation 更像是在说:

我现在要做这次状态修改,并且希望这次修改被动画化。

这个区别很关键,因为它会直接影响动画的可控性。

三、为什么很多页面动画会“莫名其妙一起动”

最常见的原因就是作用范围没收住。

例如你本来只想让一个展开区块带动画,结果:

  • 同层其他文本也跟着动
  • 父容器高度变化导致整个区域都有动画
  • 某些不相关布局也开始过渡

这通常不是 SwiftUI 在“抽风”,而是你把动画附着在了一个范围过大的状态变化或视图层级上。

所以动画写乱时,我最常回头检查的不是参数,而是:

  • 当前这层到底负责什么变化
  • 动画是不是绑在了过大的视图范围上
  • 状态变化是不是同时影响了太多布局结果

四、很多“动画不好看”,根本不是曲线问题,而是状态建模不清

有些动画看起来别扭,并不是因为你选错了 easeInOut 还是 spring,而是:

  • 状态本身设计得不清楚
  • 一次变化同时改了太多值
  • 页面布局层级不稳定

比如一次点击同时触发:

  • 展开
  • 文案切换
  • 高度变化
  • 列表重排

那最终看起来很乱,往往不是动画 API 的锅,而是你让太多不同语义的变化挤在同一次状态跳变里了。

五、什么时候更适合用 withAnimation

我更倾向于在这些场景里用它:

  • 某个用户动作触发了一次明确的状态切换
  • 我只希望这一次状态改动被动画化
  • 我想显式控制“这次变化要不要动”

比如:

  • 展开 / 收起
  • 插入 / 删除一个局部区块
  • 点击后切换某个呈现状态

它的好处是语义更清楚:
你知道动画是和这次动作直接绑定的。

六、什么时候 .animation 容易更危险

当你没有先想清楚状态影响范围时,.animation 特别容易把页面变得“哪里都在微微动”。

尤其在复杂布局里,如果一个状态变化会影响:

  • 尺寸
  • 对齐
  • 文案
  • 容器层级

那把动画直接挂在上面,很容易导致整个区域都跟着过渡。

所以 .animation 不是不能用,而是更适合那些:

  • 影响范围相对明确
  • 状态变化语义单纯
  • 局部区域稳定

的场景。

七、一个更实用的判断:这次动画是在表达“一个动作”,还是在默认修饰“一类变化”

如果是在表达一个明确动作:

  • 点开
  • 收起
  • 插入
  • 删除

那我通常更先考虑 withAnimation

如果是在修饰一类稳定的局部状态变化,才更容易考虑 .animation

这个判断很有用,因为它让你不会只盯着 API 名字,而是真正回到“动画语义”本身。

八、结论:SwiftUI 动画真正要分清的,是状态变化的边界和动画作用的边界

如果只用一句话总结,我会说:

SwiftUI 动画最重要的不是记住 .animationwithAnimation 的语法差异,而是先分清:这次动画到底是在表达某次明确动作,还是在给某类局部状态变化附加过渡效果。

一旦这两个边界清楚了,动画就会更可控;
边界不清,页面就很容易变成“到处都在动,但没有一个地方动得特别对”。