写点什么

鸿蒙特效教程 09- 深入学习 animateTo 动画

作者:苏杰豪
  • 2025-03-26
    北京
  • 本文字数:6076 字

    阅读完需:约 20 分钟

鸿蒙特效教程 09-深入学习 animateTo 动画

本教程将带领大家从零开始,一步步讲解如何讲解 animateTo 动画,并实现按钮交互效果,使新手也能轻松掌握。

效果演示

通过两个常见的按钮动画效果,深入学习 HarmonyOS Next 的 animateTo 动画,以及探索最佳实践。


  • 缩放按钮效果

  • 抖动按钮效果


一、基础准备

1.1 理解 ArkUI 中的动画机制

HarmonyOS 的 ArkUI 框架提供了强大的动画支持,常见有两种实现方式:


  • 声明式动画:通过.animation()属性直接应用于组件

  • 命令式动画:通过animateTo()方法动态改变状态触发动画


本文将主要使用animateTo()方法,因为它更灵活,能实现更复杂的动画效果。

1.2 创建基础项目结构

首先,我们创建一个基本的页面组件结构:


@Entry@Componentstruct ButtonAnimation {  // 状态变量将在后续步骤中添加    build() {    Column({ space: 20 }) {      Text('按钮交互效果')        .fontSize(22)        .fontWeight(FontWeight.Bold)              // 后续步骤将在这里添加按钮组件    }    .width('100%')    .height('100%')    .padding(20)    .backgroundColor('#ffb3d0ff')    .justifyContent(FlexAlign.Center)    .expandSafeArea()  }}
复制代码


这段代码创建了一个基本的页面布局,包含一个标题文本。接下来,我们将逐步添加按钮和动画效果。

二、实现按钮点击缩放效果

2.1 添加基础按钮布局

首先,添加一个按钮及其容器:


// 按钮缩放效果Column({ space: 10 }) {  Text('按钮点击缩放效果')    .fontSize(16)    .fontWeight(FontWeight.Medium)
Button('点击缩放') .width(150) .fontSize(16) // 动画相关属性将在后续步骤添加 .onClick(() => { // 点击处理函数将在后续步骤添加 console.log('按钮被点击了') })}.padding(16).borderRadius(12).backgroundColor('#F0F5FF').width('100%').margin({ top: 16 }).alignItems(HorizontalAlign.Center)
复制代码


这段代码添加了一个带标题的按钮区域,并为按钮设置了基本样式。

2.2 添加状态变量和缩放属性

要实现缩放效果,我们需要添加一个状态变量来控制按钮的缩放比例:


@State buttonScale: number = 1.0
复制代码


然后,为按钮添加缩放属性:


Button('点击缩放')  .width(150)  .fontSize(16)  .scale({ x: this.buttonScale, y: this.buttonScale })  // 添加缩放属性  .onClick(() => {    console.log('按钮被点击了')  })
复制代码


.scale()属性用于设置组件的缩放比例,通过改变buttonScale的值,可以实现按钮的缩放效果。

2.3 实现简单的缩放动画

现在,添加一个简单的点击缩放效果:


// 按钮点击缩放效果pressButton() {  // 缩小  animateTo({    duration: 100,  // 动画持续时间(毫秒)    curve: Curve.EaseIn  // 缓动曲线  }, () => {    this.buttonScale = 0.9  // 缩小到90%  })    // 延时后恢复原大小  setTimeout(() => {    animateTo({      duration: 200,      curve: Curve.EaseOut    }, () => {      this.buttonScale = 1.0  // 恢复原大小    })  }, 100)}
复制代码


然后修改按钮的点击处理函数:


.onClick(() => {  this.pressButton()  // 调用缩放动画函数  console.log('按钮被点击了')})
复制代码


这段代码实现了一个基本的缩放动画:按钮点击时先缩小到 90%,然后恢复原大小。但是它使用了setTimeout,我们可以进一步优化。

2.4 使用 onFinish 回调优化动画

animateTo()方法提供了onFinish回调,可以在动画完成后执行操作。我们可以使用它来替代setTimeout


@State animationCount: number = 0  // 用于跟踪动画状态
// 按钮点击缩放效果pressButton() { this.animationCount = 0 // 缩小 animateTo({ duration: 100, curve: Curve.EaseIn, // 缓入曲线 onFinish: () => { // 动画完成后立即开始第二阶段 animateTo({ duration: 200, curve: Curve.ExtremeDeceleration // 急缓曲线 }, () => { this.buttonScale = 1.0 }) } }, () => { this.animationCount++ this.buttonScale = 0.9 })}
复制代码


这种实现方式更加优雅,没有使用setTimeout,而是利用动画完成回调来链接多个动画阶段。此外,我们使用了不同的缓动曲线,使动画更加生动:


  • Curve.EaseIn:缓入曲线,动画开始时缓慢,然后加速

  • Curve.ExtremeDeceleration:急缓曲线,开始快速然后迅速减慢,产生弹性的视觉效果

三、实现按钮抖动效果

3.1 添加抖动按钮布局

先添加抖动按钮的 UI 部分:


// 抖动效果Column({ space: 10 }) {  Text('按钮抖动效果')    .fontSize(16)    .fontWeight(FontWeight.Medium)
Button('点击抖动') .width(150) .fontSize(16) // 动画相关属性将在后续步骤添加 .onClick(() => { console.log('按钮被点击了') })}.padding(16).borderRadius(12).backgroundColor('#F0F5FF').width('100%').alignItems(HorizontalAlign.Center)
复制代码

3.2 添加状态变量和位移属性

要实现抖动效果,我们需要添加状态变量来控制按钮的水平位移:


@State shakeOffset: number = 0  // 控制水平抖动偏移@State shakeStep: number = 0    // 用于跟踪抖动步骤
复制代码


然后,为按钮添加平移属性:


Button('点击抖动')  .width(150)  .fontSize(16)  .translate({ x: this.shakeOffset })  // 添加水平平移属性  .onClick(() => {    console.log('按钮被点击了')  })
复制代码


.translate()属性用于设置组件的平移,通过改变shakeOffset的值,我们可以让按钮左右移动。

3.3 使用 setTimeout 实现连续抖动

一个简单的实现方式是使用多个setTimeout来创建连续的抖动:


// 抖动效果startShake() {  // 向右移动  animateTo({ duration: 50 }, () => {    this.shakeOffset = 5  })    // 向左移动  setTimeout(() => {    animateTo({ duration: 50 }, () => {      this.shakeOffset = -5    })  }, 50)    // 向右小幅移动  setTimeout(() => {    animateTo({ duration: 50 }, () => {      this.shakeOffset = 3    })  }, 100)    // 向左小幅移动  setTimeout(() => {    animateTo({ duration: 50 }, () => {      this.shakeOffset = -3    })  }, 150)    // 回到中心  setTimeout(() => {    animateTo({ duration: 50 }, () => {      this.shakeOffset = 0    })  }, 200)}
复制代码


修改按钮的点击处理函数:


.onClick(() => {  this.startShake()  // 调用抖动动画函数  console.log('按钮被点击了')})
复制代码


这段代码通过多个setTimeout连续改变按钮的水平偏移量,实现抖动效果。但是使用这么多的setTimeout不够优雅,我们可以进一步优化。

3.4 使用递归和 onFinish 回调优化抖动动画

我们可以使用递归和onFinish回调来替代多个setTimeout,使代码更加优雅:


// 抖动效果startShake() {  this.shakeStep = 0  this.executeShakeStep()}
// 执行抖动的每一步executeShakeStep() { const shakeValues = [5, -5, 3, -3, 0] // 定义抖动序列
if (this.shakeStep >= shakeValues.length) { return // 所有步骤完成后退出 }
animateTo({ duration: 50, curve: Curve.Linear, // 匀速曲线 onFinish: () => { this.shakeStep++ if (this.shakeStep < shakeValues.length) { this.executeShakeStep() // 递归执行下一步抖动 } } }, () => { this.shakeOffset = shakeValues[this.shakeStep] // 设置当前步骤的偏移值 })}
复制代码


这种实现方式更加优雅和灵活:


  1. 使用数组shakeValues定义整个抖动序列

  2. 通过递归调用executeShakeStep()onFinish回调,实现连续动画

  3. 没有使用setTimeout,使代码更加清晰和易于维护

四、animateTo API 详解

animateTo()是 HarmonyOS 中实现动画的核心 API,它的基本语法如下:


animateTo(value: AnimateParam, event: () => void): void
复制代码

4.1 AnimateParam 参数

AnimateParam是一个配置对象,包含以下主要属性:


  • duration: number - 动画持续时间,单位为毫秒

  • tempo: number - 动画播放速度,值越大动画播放越快,默认值 1

  • curve: Curve - 动画的缓动曲线,控制动画的速度变化

  • delay: number - 动画开始前的延迟时间,单位为毫秒

  • iterations: number - 动画重复次数,-1 表示无限循环

  • playMode: PlayMode - 动画播放模式,如正向、反向、交替等

  • onFinish: () => void - 动画完成时的回调函数

4.2 常用缓动曲线

HarmonyOS 提供了多种缓动曲线,可以实现不同的动画效果:


  • Curve.Linear: 线性曲线,动画速度恒定

  • Curve.EaseIn: 缓入曲线,动画开始缓慢,然后加速

  • Curve.EaseOut: 缓出曲线,动画开始快速,然后减速

  • Curve.EaseInOut: 缓入缓出曲线,动画开始和结束都缓慢,中间快速

  • Curve.FastOutSlowIn: 快出慢入曲线,类似于 Android 的标准曲线

  • Curve.ExtremeDeceleration: 急缓曲线,用于模拟弹性效果

  • curves.springMotion(): 弹簧曲线,模拟物理弹簧效果

4.3 动画函数

event是一个函数,在这个函数中改变状态变量的值,从而触发动画。例如:


animateTo({ duration: 300 }, () => {  this.buttonScale = 0.9  // 改变状态变量,触发缩放动画})
复制代码

4.4 连续动画的实现方式

有几种方式可以实现连续的动画效果:


  1. 使用 setTimeout(不推荐):


   animateTo({ duration: 300 }, () => { this.value1 = newValue1 })   setTimeout(() => {     animateTo({ duration: 300 }, () => { this.value2 = newValue2 })   }, 300)
复制代码


  1. 使用 onFinish 回调(推荐):


   animateTo({     duration: 300,     onFinish: () => {       animateTo({ duration: 300 }, () => { this.value2 = newValue2 })     }   }, () => {     this.value1 = newValue1   })
复制代码


  1. 使用递归和计数器(用于复杂序列):


   let steps = [value1, value2, value3]   let currentStep = 0      function executeNextStep() {     if (currentStep >= steps.length) return          animateTo({       duration: 300,       onFinish: () => {         currentStep++         if (currentStep < steps.length) {           executeNextStep()         }       }     }, () => {       this.value = steps[currentStep]     })   }      executeNextStep()
复制代码

五、完整代码实现

下面是完整的按钮动画效果实现代码:


@Entry@Componentstruct ButtonAnimation {  @State buttonScale: number = 1.0  @State shakeOffset: number = 0  @State animationCount: number = 0  // 用于跟踪动画状态  @State shakeStep: number = 0  // 用于跟踪抖动步骤
// 按钮点击缩放效果 pressButton() { this.animationCount = 0 // 缩小 animateTo({ duration: 100, curve: Curve.EaseIn, // 缓入曲线 onFinish: () => { // 动画完成后立即开始第二阶段 animateTo({ duration: 200, curve: Curve.ExtremeDeceleration // 急缓曲线 }, () => { this.buttonScale = 1.0 }) } }, () => { this.animationCount++ this.buttonScale = 0.9 }) }
// 抖动效果 startShake() { this.shakeStep = 0 this.executeShakeStep() }
// 执行抖动的每一步 executeShakeStep() { const shakeValues = [5, -5, 3, -3, 0]
if (this.shakeStep >= shakeValues.length) { return }
animateTo({ duration: 50, curve: Curve.Linear, // 匀速曲线 onFinish: () => { this.shakeStep++ if (this.shakeStep < shakeValues.length) { this.executeShakeStep() // 递归执行下一步抖动 } } }, () => { this.shakeOffset = shakeValues[this.shakeStep] }) }
build() { Column({ space: 20 }) { Text('按钮交互效果') .fontSize(22) .fontWeight(FontWeight.Bold)
// 按钮缩放效果 Column({ space: 10 }) { Text('按钮点击缩放效果') .fontSize(16) .fontWeight(FontWeight.Medium)
Button('点击缩放') .width(150) .fontSize(16) .scale({ x: this.buttonScale, y: this.buttonScale }) .onClick(() => { // 缩放效果 this.pressButton() // 你的业务逻辑 console.log('你的业务逻辑') }) } .padding(16) .borderRadius(12) .backgroundColor('#F0F5FF') .width('100%') .margin({ top: 16 }) .alignItems(HorizontalAlign.Center)
// 抖动效果 Column({ space: 10 }) { Text('按钮抖动效果') .fontSize(16) .fontWeight(FontWeight.Medium)
Button('点击抖动') .width(150) .fontSize(16) .translate({ x: this.shakeOffset }) .onClick(() => { // 你的业务逻辑 console.log('你的业务逻辑') // 模拟轻微震动反馈,适用于错误提示或注意力引导 this.startShake() }) } .padding(16) .borderRadius(12) .backgroundColor('#F0F5FF') .width('100%') .alignItems(HorizontalAlign.Center) } .width('100%') .height('100%') .padding(20) .backgroundColor('#ffb3d0ff') .justifyContent(FlexAlign.Center) .expandSafeArea() }}
复制代码

六、应用场景和扩展

6.1 适用场景

  • 缩放效果:适用于提供用户点击反馈,增强交互感

  • 抖动效果:适用于错误提示、警告或引起用户注意

6.2 可能的扩展

  1. 结合振动反馈:与设备振动结合,提供触觉反馈

  2. 添加声音反馈:配合音效,提供听觉反馈

  3. 组合多种动画:如缩放+旋转、缩放+颜色变化等

6.3 性能优化建议

  1. 避免过于复杂的动画,尤其是在低端设备上

  2. 合理选择动画持续时间,一般不超过 300ms

  3. 对于频繁触发的动画,考虑增加防抖处理

  4. 使用onFinish回调代替setTimeout实现连续动画

七、总结与心得

通过本文,我们学习了如何在 HarmonyOS 中实现按钮缩放和抖动效果,关键点包括:


  1. 使用@State状态变量控制动画参数

  2. 利用animateTo()方法实现流畅的状态变化动画

  3. 选择合适的缓动曲线让动画更加自然

  4. 使用onFinish回调和递归实现连续动画,避免使用setTimeout

  5. 将动画逻辑封装为独立方法,使代码更加清晰


动画效果能够显著提升应用的用户体验,希望本文能帮助你在 HarmonyOS 应用中添加生动、自然的交互动画。随着你对 animateTo() API 的深入理解,可以创造出更加复杂和精美的动画效果。


希望这篇 HarmonyOS Next 教程对你有所帮助,期待您的点赞、评论、收藏。

发布于: 1 小时前阅读数: 10
用户头像

苏杰豪

关注

鸿蒙很开门~ 2019-03-30 加入

传智教育、黑马程序员课程研究员

评论

发布
暂无评论
鸿蒙特效教程09-深入学习animateTo动画_鸿蒙_苏杰豪_InfoQ写作社区