news 2026/6/9 11:45:10

动画曲线详解:HarmonyOS6 PC选对曲线让动效更丝滑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
动画曲线详解:HarmonyOS6 PC选对曲线让动效更丝滑

我曾经花了一整个下午,就为了调一个按钮的点击动画。代码逻辑没问题,状态切换没问题,时长也没问题——但就是觉得"不对味"。后来我把动画曲线从 Linear 换成了 FastOutSlowIn,瞬间就舒服了。那一刻我才真正理解:动画曲线才是动效的灵魂。

很多人写动画的时候,习惯性地用 Linear 或者 EaseInOut,然后觉得所有动画都"差不多"。其实 HarmonyOS6 PC 提供了相当丰富的曲线类型,每种曲线都有自己独特的"性格"。选对了曲线,300毫秒的动画比1秒的还好看;选错了曲线,再长的动画也像是在凑时间。

今天这篇文章,我把 Curve 枚举里的每种曲线都讲透,配上对比代码,让你能直观感受不同曲线的差异。

什么是动画曲线

在我们深入之前,先建立一个直觉。动画曲线本质上就是一个函数:输入是时间进度(0到1),输出是动画进度(也是0到1)。

如果是 Linear(线性)曲线,时间过了一半,动画也走了一半——匀速运动。如果是 EaseOut 曲线,时间过了一半,动画可能已经走了80%——前面快后面慢。曲线决定了动画在每一刻的"速度",这就是为什么同样的起止状态和时长,不同曲线给人的感觉完全不同。

你可以把动画曲线想象成开车的油门控制。Linear 是匀速踩油门,车匀加速匀减速。EaseIn 是先轻踩后重踩,车慢慢起步然后猛加速。EaseOut 是先重踩后松油门,车猛冲出去然后慢慢停下。

Curve 枚举全览

HarmonyOS6 PC 的 Curve 枚举提供了以下常用曲线类型:

  • Curve.Linear— 线性,匀速
  • Curve.Ease— 默认缓动,略带 EaseIn 和 EaseOut
  • Curve.EaseIn— 缓入,慢起步
  • Curve.EaseOut— 缓出,慢停车
  • Curve.EaseInOut— 缓入缓出,两头慢中间快
  • Curve.FastOutSlowIn— 快出慢入,前段快速后段缓慢
  • Curve.LinearOutSlowIn— 线性起步,慢速结束
  • Curve.FastOutLinearIn— 快速起步,线性结束
  • Curve.ExtremeDeceleration— 极端减速
  • Curve.Sharp— 尖锐曲线
  • Curve.Rhythm— 节奏曲线

逐个击破:每种曲线的性格

Linear:毫无感情的匀速机器
Column().width(60).height(60).backgroundColor('#FF6B6B').borderRadius(12).translate({x:this.offsetX}).animation({duration:1000,curve:Curve.Linear})

Linear 曲线的输出和时间完全成正比。时间过了30%,动画就走了30%;时间过了70%,动画就走了70%。没有任何加速或减速。

这种"诚实"的匀速运动,在自然界中几乎不存在——现实中的物体要么在加速,要么在减速,很少有真正匀速的。所以 Linear 动画给人的感觉是"机械的"、“人工的”。

但这不代表 Linear 没用。它在以下场景非常合适:

  • 持续旋转(风扇、loading转圈),匀速旋转才自然
  • 进度条匀速增长(表示稳定的处理过程)
  • 无限循环动画(避免每个循环之间有速度突变)
// 匀速旋转的loadingColumn().width(40).height(40).rotate({angle:this.rotateAngle}).animation({duration:1000,curve:Curve.Linear,iterations:-1})
EaseIn:优雅的起步
Column().width(60).height(60).backgroundColor('#FFD93D').borderRadius(12).translate({x:this.offsetX}).animation({duration:1000,curve:Curve.EaseIn})

EaseIn 曲线在开始时变化很慢,然后逐渐加速,到结束时达到最快速度。数学上近似于二次函数或三次函数

这种曲线适合"离场"动画——元素要离开屏幕时,先慢慢起步,然后加速飞走。就像你扔一个球出去,球在出手的那一刻是逐渐加速的。

// 元素向右飞出屏幕Button('发送').translate({x:this.flyOffX}).animation({duration:500,curve:Curve.EaseIn}).onClick(()=>{this.flyOffX=500// 加速飞出})

不适合的场景是"进场"或"点击反馈"——一个元素从外面慢慢起步飞进来,会给人一种"犹豫"的感觉。

EaseOut:稳重的停车
Column().width(60).height(60).backgroundColor('#4ECDC4').borderRadius(12).translate({x:this.offsetX}).animation({duration:1000,curve:Curve.EaseOut})

EaseOut 和 EaseIn 恰好相反:开始变化很快,然后逐渐减速,到结束时完全停下来。数学上近似于1 - (1-t)²1 - (1-t)³

这是最常用的曲线类型,没有之一。因为绝大多数"进场"动画都适合 EaseOut——元素从外面快速滑入,然后缓缓停在目标位置。这和我们在现实世界中看到的情景一致:一个物体滑过来,摩擦力让它慢慢停下。

// 通知从右侧滑入Column(){Text('新消息')}.translate({x:this.notifyX}).animation({duration:400,curve:Curve.EaseOut}).onAppear(()=>{this.notifyX=300// 初始在屏幕外this.notifyX=0// 滑入到目标位置})

EaseOut 也特别适合点击反馈。按钮被按下后弹回的过程,用 EaseOut 就很自然——快速弹起,慢慢稳定。

EaseInOut:对称的呼吸感
Column().width(60).height(60).backgroundColor('#6BCB77').borderRadius(12).translate({x:this.offsetX}).animation({duration:1000,curve:Curve.EaseInOut})

EaseInOut 结合了 EaseIn 和 EaseOut 的特点:起步慢,中间快,结束慢。数学上就是 EaseIn 和 EaseOut 的分段组合。

这种曲线最大的特点是"对称感"。它没有明显的"快起步"或"快结束",整体感觉比较平衡。适合以下场景:

  • 状态切换(展开/折叠、开/关)
  • 大小变化(放大/缩小)
  • 透明度渐变(淡入/淡出)
// 手风琴展开效果Column(){// 折叠内容}.height(this.expandedHeight).animation({duration:350,curve:Curve.EaseInOut})

EaseInOut 的对称性既是优点也是缺点。它很"安全",用在哪儿都不会出错,但也缺少个性。如果你想要更鲜明的动效风格,可以考虑 FastOutSlowIn。

FastOutSlowIn:前冲后缓的活力曲线
Column().width(60).height(60).backgroundColor('#4D96FF').borderRadius(12).translate({x:this.offsetX}).animation({duration:1000,curve:Curve.FastOutSlowIn})

FastOutSlowIn 的特点很明确:前段变化非常快(大概30%的时间内完成了70%的动画),后段变化非常慢(剩余70%的时间里慢慢完成最后30%的动画)。

这种曲线比 EaseOut 更"激进"。它起步更快,给人一种"立刻响应"的感觉,然后慢慢稳定下来。在 Material Design 中,这条曲线被称为"标准曲线",大量用于各种交互动画。

// 按钮点击反馈Button('确认').scale({x:this.btnScale,y:this.btnScale}).animation({duration:300,curve:Curve.FastOutSlowIn}).onMouseDown(()=>{this.btnScale=0.95}).onMouseUp(()=>{this.btnScale=1.0})

FastOutSlowIn 特别适合弹性类动画的前半段。配合 setTimeout 做"弹出去再回来"的效果时,FastOutSlowIn 让弹出那一步非常干脆。

LinearOutSlowIn:平稳起步,柔和结束
Column().width(60).height(60).backgroundColor('#9B59B6').borderRadius(12).translate({x:this.offsetX}).animation({duration:1000,curve:Curve.LinearOutSlowIn})

这条曲线前半段接近线性(匀速),后半段逐渐减速。可以理解为"正常速度走,然后慢慢停下来"。

它比 EaseOut 更"温和",因为起步不是那么冲。适合那些需要匀速运动一段再停下的场景,比如侧边栏的展开——先匀速推出,到位时缓缓停住。

// 侧边栏展开Column(){// 侧边栏内容}.translate({x:this.sideBarX}).animation({duration:400,curve:Curve.LinearOutSlowIn})
FastOutLinearIn:快速启动,匀速结束
Column().width(60).height(60).backgroundColor('#FF6B9D').borderRadius(12).translate({x:this.offsetX}).animation({duration:1000,curve:Curve.FastOutLinearIn})

和 LinearOutSlowIn 相反,这条曲线前段很快,后段变成线性。适合"快速响应然后保持速度离开"的场景,主要用于离场动画。

// 卡片向左滑出删除Column(){Text('待删除项')}.translate({x:this.cardX}).animation({duration:350,curve:Curve.FastOutLinearIn}).gesture(PanGesture({direction:PanDirection.Horizontal}).onActionEnd(()=>{this.cardX=-400// 快速飞出}))

同场景对比:感受曲线差异

理论讲再多不如亲自看效果。我们来做一个对比实验:让同一个方块做同样的位移动画,只是换不同的曲线,直观感受差异。

@Entry@Componentstruct CurveCompareDemo{@Stateoffsets:Record<string,number>={'Linear':0,'EaseIn':0,'EaseOut':0,'EaseInOut':0,'FastOutSlowIn':0}privatecurves:Record<string,Curve>={'Linear':Curve.Linear,'EaseIn':Curve.EaseIn,'EaseOut':Curve.EaseOut,'EaseInOut':Curve.EaseInOut,'FastOutSlowIn':Curve.FastOutSlowIn}privatecolors:string[]=['#FF6B6B','#FFD93D','#4ECDC4','#6BCB77','#4D96FF']build(){Column(){Text('曲线对比').fontSize(18).fontWeight(FontWeight.Bold).margin({bottom:16})ForEach(Object.keys(this.offsets),(name:string,index:number)=>{Row(){Text(name).fontSize(11).fontColor('#666666').width(110)Stack({alignContent:Alignment.Start}){Column().width('100%').height(4).backgroundColor('#E8E8E8').borderRadius(2)Column().width(28).height(28).borderRadius(14).backgroundColor(this.colors[index]).translate({x:this.offsets[name],y:-12}).animation({duration:1200,curve:this.curves[name]})}.width('70%')}.width('100%').margin({bottom:16}).alignItems(VerticalAlign.Center)})Row({space:12}){Button('开始动画').onClick(()=>{Object.keys(this.offsets).forEach((name)=>{this.offsets[name]=200})})Button('重置').onClick(()=>{Object.keys(this.offsets).forEach((name)=>{this.offsets[name]=0})})}.width('100%').justifyContent(FlexAlign.Center).margin({top:16})}.width('100%').height('100%').backgroundColor('#F5F6FA').padding(20)}}

点击"开始动画"后,五个圆球同时从左边出发到右边,但各自使用不同的曲线。你会清晰地看到:

  • Linear 匀速前进,不快不慢
  • EaseIn 起步很慢,后半段猛冲
  • EaseOut 起步猛冲,慢慢停下
  • EaseInOut 两头慢中间快
  • FastOutSlowIn 起步最快,后段减速最明显

这个对比demo非常值得你亲手跑一遍。视觉上的差异比任何文字描述都直观。

曲线选择的决策指南

讲了这么多曲线,实际项目中怎么选?我总结了一套简单的决策逻辑:

元素进入场景

进场动画一律用减速类曲线:EaseOut、FastOutSlowIn、LinearOutSlowIn。

  • 从屏幕外滑入:用 EaseOut(模拟减速停车)
  • 从中心弹出:用 FastOutSlowIn(快速弹开,慢慢稳定)
  • 淡入出现:用 EaseInOut(透明度过渡要柔和)
元素离开场景

离场动画用加速类曲线:EaseIn、FastOutLinearIn。

  • 向屏幕外滑出:用 EaseIn(慢慢起步,加速飞走)
  • 缩小消失:用 EaseIn(越来越快,直到看不见)
状态切换

在两个状态之间切换用对称类曲线:EaseInOut、Linear。

  • 展开/折叠:用 EaseInOut(对称,不偏不倚)
  • 颜色变化:用 EaseInOut(颜色过渡要平滑)
  • 持续旋转/闪烁:用 Linear(保持恒定节奏)
交互反馈

用户操作的反馈用快速响应类曲线:FastOutSlowIn。

  • 按钮点击:用 FastOutSlowIn(立刻响应,缓缓回位)
  • 缩放弹跳:用 FastOutSlowIn(弹出干脆,稳定柔和)
  • 拖拽释放:用 EaseOut(快速回位,慢慢停稳)

自定义曲线的进阶玩法

如果 Curve 枚举里的预设曲线都不能满足你的需求,HarmonyOS6 PC 还支持自定义贝塞尔曲线:

.animation({duration:500,curve:Curve.EaseOut// 使用预设})// 或者使用自定义三次贝塞尔曲线.animation({duration:500,curve:curves.cubicBezier(0.17,0.67,0.83,0.67)})

贝塞尔曲线的四个参数定义了两个控制点的坐标。你可以用在线贝塞尔曲线编辑器(比如 cubic-bezier.com)来可视化地调整曲线形状,然后把参数值填进来。

还有一种更高级的 spring 弹簧曲线:

.animation({duration:500,curve:curves.springMotion(0.3,0.8)})

弹簧曲线模拟真实的弹簧物理行为,第一个参数是阻尼比(越小弹得越厉害),第二个参数是刚度(越大弹得越快)。如果你想做iOS那种"果冻弹"的效果,弹簧曲线是你的最佳选择。

// iOS风格的弹性回弹Button('弹性按钮').scale({x:this.springScale,y:this.springScale}).animation({duration:800,curve:curves.springMotion(0.25,0.7)}).onMouseDown(()=>{this.springScale=0.85}).onMouseUp(()=>{this.springScale=1.0})

阻尼比0.25意味着弹簧会来回弹几次才停下来,配合0.7的刚度,整个效果非常有弹性。这种效果在 HarmonyOS6 PC 端的卡片交互中特别好用。

常见误区

分享几个我自己踩过的坑:

误区一:所有动画都用同一个曲线。我见过有的项目全局用 EaseInOut,结果进场动画不够冲,离场动画不够快,点击反馈不够弹。不同场景需要不同曲线,别偷懒。

误区二:忽略时长和曲线的配合。FastOutSlowIn 配合200毫秒的时长,和配合800毫秒的时长,效果天差地别。短时长配合快曲线会很急促,长时长配合慢曲线会很优雅。要一起调。

误区三:动画曲线越复杂越好。不是的。一个简单的 EaseOut 配合合适的时长,往往比精心调制的弹簧曲线效果更好。动画的目的是服务用户体验,不是炫技。

误区四:Linear 是万能的。Linear 的适用范围其实很窄——只有需要"恒定速度"的场景才该用它。把 Linear 用在位移动画上,会让人觉得元素在"滑行"而不是"运动"。

曲线调参的实用技巧

调动画曲线是个经验活,但也有一些可量化的方法:

用手机录像功能录下你觉得"好用"的App的动画,然后逐帧回放,观察它的速度变化规律。你会发现大部分优秀App的动画都在用类似的曲线——起步快、结束慢,这就是 EaseOut 和 FastOutSlowIn 的领地。

在 HarmonyOS6 PC 上做开发时,给动画加一个调试模式:把 duration 放大到2000毫秒,这样你能清楚地看到曲线在每个阶段的速度变化。调好曲线后再把时长缩短到合理值。

把常用的曲线配置抽成常量,在项目中复用。比如定义一个ANIM_STANDARD代表标准曲线(FastOutSlowIn, 300ms),ANIM_ENTER代表进场曲线(EaseOut, 400ms),这样整个项目的动画风格会保持一致。

动画曲线是 HarmonyOS6 PC 开发中最容易被忽视、但影响最大的细节。希望这篇文章能帮你建立对曲线的直觉,下次写动画的时候,不再是无脑 Linear,而是胸有成竹地选出最合适的那一条。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 11:42:40

告别重复劳动:3分钟学会用KeymouseGo解放双手的终极指南

告别重复劳动&#xff1a;3分钟学会用KeymouseGo解放双手的终极指南 【免费下载链接】KeymouseGo 类似按键精灵的鼠标键盘录制和自动化操作 模拟点击和键入 | automate mouse clicks and keyboard input 项目地址: https://gitcode.com/gh_mirrors/ke/KeymouseGo 还在为…

作者头像 李华
网站建设 2026/6/9 11:42:18

从一个物料主数据权限场景看懂 SAP Role Administration 的设计方法

今天我们从一个很典型的 SAP 授权场景切入,业务部门正在使用 SD 和 MM,但是没有启用 HR,也没有启用 HR-ORG,MM 里也没有使用 Warehouse Management。公司一共有五个 plant,现在准备在这些 plant 里维护 material master data。业务上的要求很清楚,每个 plant 都有一个专门…

作者头像 李华