一、鸿蒙动画概述

在移动应用开发中,动画是提升用户体验的核心手段之一。流畅、自然的动画效果能让应用界面更具生动性和交互感,有效降低用户操作的生硬感,增强应用的易用性与吸引力。

ArkUI 提供了丰富的动画接口,核心包括属性动画、转场动画、粒子动画等,其核心原理是:驱动组件属性值按照预设的动画参数,从起始值逐步过渡到终点值。尽管属性值的变化本质上具有一定离散性,但借助人眼的视觉暂留效应,最终呈现出连续流畅的动画效果。

UI 界面的每一次更新称为一个动画帧,对应一次屏幕刷新,而帧率(FPS,Frames Per Second)是衡量动画流畅度的关键指标——帧率越高,动画越顺滑,用户视觉体验越好。

动画接口分类与作用

动画类型 作用 特点
属性动画 最基础的动画类型,由系统驱动属性逐帧变化,生成连续动画效果 除自定义属性动画外,应用侧无需感知动画过程
转场动画 为组件的出现、消失提供过渡效果 部分接口内置固定动画曲线,不支持开发者自定义,以保证动画一致性
粒子动画 实现粒子特效 丰富视觉效果,提升交互体验
组件动画 组件自带默认动效(如 List 滑动动效) 同时部分组件支持自定义动效,降低开发成本
帧动画 系统提供动画过程中的插值结果,由开发者每帧修改属性值生成动画 支持暂停操作,但性能表现稍弱

在鸿蒙众多动画 API 中,属性动画是最常用、最基础的类型,也是本文的核心讲解重点。

二、鸿蒙属性动画介绍

属性接口(简称“属性”)涵盖尺寸、布局、位置、外观等多种类型,用于控制组件的显示形态与行为。对于当前界面中的组件,其部分属性(如位置、透明度)的变化会直接触发 UI 刷新,而**属性动画的作用,就是让这些属性值从起点平滑过渡到终点,避免 UI 突变带来的生硬感**。

可动画属性与不可动画属性

根据属性变化是否适合添加动画,可将其分为**可动画属性不可动画属性**:

可动画属性
分类 说明
布局属性 位置、大小、内边距、外边距、对齐方式、权重等,直接影响组件在界面中的布局形态
仿射变换 平移、旋转、缩放、锚点等,用于实现组件的空间变换效果
背景 背景颜色、背景模糊等,影响组件的背景呈现效果
内容 文字大小、文字颜色,图片对齐方式、模糊效果等,与组件内部内容的显示相关
前景 前景颜色等,覆盖在组件内容之上的视觉效果
Overlay Overlay 相关属性,用于实现组件的叠加显示效果
外观 透明度、圆角、边框、阴影等,直接影响组件的视觉外观
其他 其他系统支持的可动画属性,根据具体版本及组件特性有所扩展
不可动画属性

zIndex(层级)、focusable(焦点控制)、enabled(交互开关)等,这类属性变化不适合添加动画,需立即生效。

核心概念

  1. 属性动画:通过改变组件的可动画属性值实现动画效果,是鸿蒙系统中最基础、最常用的动画类型,无需开发者手动控制每帧变化。
  2. 动画参数:控制动画播放的核心配置,包括动画持续时间、曲线类型、重复次数、播放模式、延迟时间等。
  3. 动画曲线:定义属性值变化的速度规律,直接决定动画的“运动质感”,如匀速、缓入缓出、弹簧振动等。
  4. 动画状态:动画生命周期中的不同阶段,包括开始、进行中、暂停、结束等,开发者可根据需求监听状态变化。

核心动画参数详解

参数 类型 说明 默认值
duration number 动画持续时间,单位为毫秒(ms),决定动画从开始到结束的耗时 -
curve Curve 动画曲线,定义属性值变化的速度规律,是决定动画质感的核心参数 Curve.Linear(线性)
delay number 动画延迟时间,单位为毫秒(ms),即触发动画后,延迟多久开始播放 0
iterations number 动画重复次数,取值为正整数,-1 表示无限循环播放 1
playMode PlayMode 动画播放模式,包括正向(Normal)、反向(Reverse)、交替(Alternate)等,控制动画重复播放时的方向 PlayMode.Normal

常见动画曲线类型

曲线类型 说明 适用场景
Curve.Linear 线性动画,属性值匀速变化,速度保持不变 简单的平移、旋转,需要匀速运动的场景
Curve.Ease 缓入缓出动画,开始和结束时速度较慢,中间速度较快,过渡自然 大部分通用场景,如组件显示/隐藏、按钮点击反馈
Curve.EaseIn 缓入动画,开始时速度较慢,逐渐加快 组件入场、从远到近的运动效果
Curve.EaseOut 缓出动画,开始时速度较快,逐渐减慢 组件退场、从近到远的运动效果
Curve.EaseInOut 缓入缓出动画,与 Ease 效果类似,过渡更细腻 需要细腻过渡的场景,如弹窗动画、卡片切换
Curve.Friction 摩擦动画,模拟物体受到摩擦力逐渐减速的效果,自然收尾 拖拽后的回弹、物体落地的缓冲效果
Curve.Spring 弹簧动画,模拟弹簧振动的效果,带有轻微回弹 需要弹性反馈的场景,如按钮点击、组件回弹

三、鸿蒙属性动画的实现方式

属性动画的核心是通过动画接口驱动组件属性变化,ArkUI 提供了三种核心动画接口——animation、animateTo、keyframeAnimateTo,分别适用于不同场景,可灵活实现各类属性动画效果。

动画接口 作用域 原理 使用场景
animation 组件通过属性接口绑定的属性变化 自动识别组件的可动画属性变化,为其添加动画;组件接口调用自上而下执行,animation 仅作用于其上方的属性调用,支持为多个属性设置不同动画参数 对多个可动画属性配置不同动画参数的场景,需为单个组件的不同属性设置差异化动画
animateTo 闭包内改变属性引起的界面变化 通用函数,对比闭包执行前与闭包内状态变量引起的 UI 差异,为差异部分添加动画;支持多次调用、嵌套使用,闭包内所有属性变化遵循相同动画参数 对多个可动画属性配置相同动画参数的场景,需要嵌套动画的场景;多段动画循环可通过 playMode 和 iterations 实现
keyframeAnimateTo 多个闭包内改变属性引起的分段属性动画 通用函数,每一段闭包中的状态变量与前一次状态的差异,单独生成一段动画;支持多次调用,不推荐嵌套,每段动画可单独配置参数 同一属性需要实现连续多个动画的场景,避免多次创建动画导致的衔接卡顿

1. 基本属性动画(animation)

animation 是最简洁的属性动画实现方式,直接在组件上设置 animation 属性,即可为组件的可动画属性变化添加动画效果,无需额外复杂配置,适合简单场景的快速实现。

核心步骤:声明状态变量 → 将状态变量绑定到组件可动画属性 → 设置 animation 动画参数 → 触发状态变量变化,触发动画。

import { curves } from '@kit.ArkUI';
@Entry
@Component
struct AttrAnimationDemo3 {
  @State animate: boolean = false;
  // 第一步: 声明相关状态变量,绑定组件可动画属性
  @State rotateValue: number = 0; // 组件一旋转角度
  @State translateX: number = 0; // 组件二水平偏移量
  @State opacityValue: number = 1; // 组件透明度

  // 第二步:将状态变量绑定到组件的可动画属性上
  build() {
    Row() {
      // 组件一:旋转+透明度动画
      Column() {
      }
      .opacity(this.opacityValue)
      .rotate({ angle: this.rotateValue })
      // 第三步:设置animation属性,配置动画参数
      .animation({ curve: curves.springMotion() })
      .backgroundColor('#317AF7')
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .borderRadius(30)
      .onClick(() => {
        this.animate = !this.animate;
        // 第四步:修改状态变量,触发属性变化,进而触发动画
        this.rotateValue = this.animate ? 90 : 0; // 旋转动画
        this.translateX = this.animate ? 50 : 0; // 组件二偏移动画
        this.opacityValue = this.animate ? 0.6 : 1; // 透明度动画
      })

      // 组件二:平移+透明度动画
      Column() {
      }
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .backgroundColor('#D94838')
      .borderRadius(30)
      .opacity(this.opacityValue)
      .translate({ x: this.translateX })
      .animation({ curve: curves.springMotion() })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

说明:点击组件一后,状态变量发生变化,组件一的 rotate 属性、组件二的 translate 和 opacity 属性随之变化,animation 接口自动为这些属性变化添加弹簧动画,实现平滑过渡。

2. 显式动画(animateTo)

animateTo 是显式动画接口,通过传入动画参数和闭包函数,闭包内所有属性变化将遵循统一的动画参数,适合需要为多个组件、多个属性设置相同动画效果的场景,支持嵌套使用,灵活性更高。

接口定义

animateTo(value: AnimateParam, event: () => void): void

参数说明:value 为动画参数配置(AnimateParam 对象),event 为闭包函数,闭包内的状态变量变化所引发的 UI 差异,将自动应用该动画参数。

import { curves } from '@kit.ArkUI';
@Entry
@Component
struct AttrAnimateToDemo2 {
  @State animate: boolean = false;
  // 第一步: 声明相关状态变量
  @State rotateValue: number = 0; // 组件一旋转角度
  @State translateX: number = 0; // 组件二水平偏移量
  @State opacityValue: number = 1; // 组件透明度

  // 第二步:将状态变量绑定到组件可动画属性
  build() {
    Row() {
      // 组件一
      Column() {
      }
      .rotate({ angle: this.rotateValue })
      .backgroundColor('#317AF7')
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .borderRadius(30)
      .onClick(() => {
        // 第三步:调用animateTo接口,配置动画参数和闭包
        this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => {
          this.animate = !this.animate;
          // 闭包内修改状态变量,所有属性变化遵循相同动画参数
          this.rotateValue = this.animate ? 90 : 0; // 组件一旋转
          this.opacityValue = this.animate ? 0.6 : 1; // 组件二透明度
          this.translateX = this.animate ? 50 : 0; // 组件二平移
        })
      })

      // 组件二
      Column() {
      }
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .backgroundColor('#D94838')
      .borderRadius(30)
      .opacity(this.opacityValue)
      .translate({ x: this.translateX })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

说明:与 animation 接口不同,animateTo 将动画参数统一配置在接口中,闭包内所有属性变化(旋转、平移、透明度)均使用相同的弹簧曲线,无需为每个组件单独设置 animation,适合批量控制动画效果。

3. 关键帧动画(keyframeAnimateTo)

keyframeAnimateTo 用于实现分段动画,通过传入整体动画参数和关键帧数组,每一段关键帧可单独配置时长、曲线等参数,适合同一属性需要连续执行多个动画的场景,避免多次创建动画导致的衔接卡顿。

接口定义

keyframeAnimateTo(param: KeyframeAnimateParam, keyframes: Array<KeyframeState>): void

参数说明:param 为关键帧动画整体参数(如重复次数、延迟、结束回调);keyframes 为关键帧数组,每一项包含当前关键帧的时长、曲线、闭包事件(属性变化逻辑)。

@Entry
@Component
struct KeyframeAnimateToDemo {
  // 第一步: 声明相关状态变量
  @State rotateValue: number = 0; // 组件一旋转角度
  @State translateX: number = 0; // 组件二水平偏移量
  @State opacityValue: number = 1; // 组件透明度

  // 第二步:将状态变量绑定到组件可动画属性
  build() {
    Row() {
      // 组件一
      Column() {
      }
      .rotate({ angle: this.rotateValue })
      .backgroundColor('#317AF7')
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .borderRadius(30)
      .onClick(() => {
        // 第三步:调用keyframeAnimateTo接口,配置整体参数和关键帧数组
        this.getUIContext()?.keyframeAnimateTo({
          iterations: 1 // 整体动画重复次数
        }, [
          {
            // 第一段关键帧:800ms,弹簧曲线,属性变化
            duration: 800,
            curve: curves.springMotion(),
            event: () => {
              this.rotateValue = 90; // 组件一顺时针旋转90度
              this.opacityValue = 0.6; // 组件二透明度降低
              this.translateX = 50; // 组件二向右偏移50px
            }
          },
          {
            // 第二段关键帧:500ms,缓出曲线,属性恢复
            duration: 500,
            curve: Curve.EaseOut,
            event: () => {
              this.rotateValue = 0; // 组件一恢复初始角度
              this.opacityValue = 1; // 组件二透明度恢复
              this.translateX = 0; // 组件二恢复初始位置
            }
          }
        ]);
      })

      // 组件二
      Column() {
      }
      .justifyContent(FlexAlign.Center)
      .width(100)
      .height(100)
      .backgroundColor('#D94838')
      .borderRadius(30)
      .opacity(this.opacityValue)
      .translate({ x: this.translateX })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

说明:点击组件一后,将依次执行两段关键帧动画:第一段 800ms 实现组件旋转、偏移和透明度变化,第二段 500ms 实现属性恢复,两段动画衔接自然,无卡顿,适合需要多阶段动画的场景(如复杂的组件交互反馈)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、项目实战:喵屿应用中的属性动画

喵屿是一款宠物管理类应用,为提升用户体验,应用中广泛运用属性动画,实现了生动的交互效果和视觉反馈。以下结合具体代码示例,讲解属性动画在实际项目中的落地方式、优化策略及最终效果。

1. 应用中的动画实现

喵屿应用的动画设计遵循“简洁、自然、贴合场景”的原则,重点运用 animation 和 animateTo 接口,实现了主页面猫咪交互、设置页面列表入场等核心动画效果。

1.1 主页面猫咪交互动画

主页面的猫咪头像为核心交互元素,点击后实现“躲起-随机出现”的动画效果,增强应用的趣味性,采用 animation 接口实现,结合定时器控制属性变化时序。

代码实现(MainPage.ets)

Image($r(`[resource].media.${this.curPet}`))
  .width(70)
  .height(100)
  .objectFit(ImageFit.Cover)
  .draggable(false) // 禁止图片手势拖动(默认值为true)
  .visibility(this.showPet ? Visibility.Visible : Visibility.None)
  // 绑定位置属性,控制猫咪的x、y坐标
  .position({ x: this.catX, y: this.windowHeight - this.listHeight - this.catOffsetY })
  // 配置动画参数,实现自然过渡
  .animation({
    duration: 800, // 动画持续800ms,过渡流畅
    curve: Curve.Friction, // 摩擦曲线,模拟自然减速效果
    iterations: 1, // 仅播放一次
    playMode: PlayMode.Normal // 正向播放
  })
  .clickEffect({ level: ClickEffectLevel.HEAVY, scale: 0.9 }) // 点击反馈效果
  .onClick(() => {
    VibrateUtil.buttonVibrate(VibrateEffect.soft); // 结合震动反馈,增强交互感
    // 第一步:猫咪“躲起”(y坐标上移)
    this.catOffsetY = -100;
    // 随机生成猫咪出现的x坐标
    this.randomCatX();
    // 第二步:1s后猫咪随机位置出现(y坐标下移)
    setTimeout(() => {
      this.catOffsetY = 50 + Math.random() * 30;
    }, 1000);
    // 第三步:1.5s后猫咪恢复初始高度
    setTimeout(() => {
      this.catOffsetY = 37;
    }, 1500);
  })

效果说明:点击猫咪头像后,猫咪先向下“躲起”(y坐标偏移量变为-100),1秒后在随机x坐标位置向下出现(y坐标偏移量随机在50~80之间),1.5秒后恢复初始高度;动画采用摩擦曲线,过渡自然不突兀,结合震动反馈,提升用户交互体验。
在这里插入图片描述

1.2 设置页面列表入场动画

设置页面的列表项采用“顺序入场”动画,通过为不同列表项设置不同的动画延迟,实现层次感和流动感,提升页面加载时的视觉体验,采用 animation 接口实现。

代码实现(Settings.ets)

ListItem() {
  this.listItem(item); // 列表项内容组件
}
.padding({ left: 16, right: 16 })
.width(CommonConstants.FULL_SIZE)
// 绑定透明度和偏移量属性,控制入场效果
.opacity(this.isShow ? 1 : 0)
.translate({ x: this.isShow ? 0 : 100 })
// 配置入场动画参数,设置延迟实现顺序效果
.animation({
  duration: 500, // 动画持续500ms
  delay: index * 50, // 每一项延迟50ms入场,形成顺序效果
  curve: Curve.EaseOut // 缓出曲线,入场更自然
})

效果说明:页面加载时,isShow 状态变为 true,列表项从右侧(x偏移100px)、透明(opacity=0)状态,逐步过渡到正常状态;由于每一项的动画延迟为 index*50ms,列表项将按顺序依次入场,形成流畅的流动感,避免所有列表项同时入场的生硬感。
在这里插入图片描述
注:入场动画建议使用转场动画实现,此处实现仅为作为对比,详情见主页《从基础到实战:鸿蒙 ArkUI 转场动画开发指南》

2. 动画优化策略

在实际项目开发中,动画的流畅性直接影响用户体验,若动画卡顿、延迟,会降低应用的专业度。喵屿应用在属性动画开发中,结合鸿蒙系统特性,采用了以下优化策略,兼顾动画效果与性能。

核心优化策略

  1. 合理设置动画时长:根据动画场景的复杂度,设置适配的时长——简单交互(如按钮点击)设置 300~500ms,复杂动画(如猫咪交互)设置 600~800ms,避免过长导致等待感,过短导致过渡突兀。

  2. 精准选择动画曲线:结合场景选择合适的曲线,如猫咪交互用 Curve.Friction 模拟自然减速,列表入场用 Curve.EaseOut 实现平滑过渡,弹性反馈用 Curve.Spring,让动画更贴合真实物理规律,提升自然感。

  3. 避免过度动画:核心交互场景(如点击、页面切换)使用动画增强反馈,非核心场景(如普通文本刷新)不添加动画,避免视觉疲劳和性能消耗。

  4. 巧用动画延迟:在列表、网格等多元素场景中,为不同元素设置递增的动画延迟,创造层次感和流动感,同时避免多元素同时动画导致的性能压力。

  5. 结合震动反馈:动画触发时,搭配轻微的震动反馈(如猫咪点击、按钮点击),增强用户的触觉交互,让动画反馈更立体。

  6. 优先选择低开销属性:组件位置、大小变化(如 translate、scale)中,scale 属性不会触发布局测量,性能开销远低于 layout 相关属性;在组件大小、位置连续变化的场景(如跟手交互),优先使用 scale 替代 layout 属性,提升动画流畅度。

  7. 区分动画类型场景:属性动画仅作用于“始终存在”的组件;组件出现、消失的动画,应使用转场动画,避免属性动画导致的卡顿或异常。

  8. 谨慎使用动画结束回调:属性动画由系统驱动,无需开发者手动处理结束逻辑;若必须使用结束回调,需妥善处理连续操作的数据管理,避免时序错乱。

  9. 适配系统场景:当系统开发者选项中关闭过渡动画,或 UIAbility 从前台切换至后台时,动画会立即执行结束回调;需对这类场景进行验证,避免在结束回调中加入时序相关的核心逻辑(如页面跳转、数据请求)。

五、总结

鸿蒙属性动画是基于组件属性变化实现的基础动画类型,也是鸿蒙应用开发中最常用的动画方式,其核心优势在于:

  • 简单易用:通过声明式的方式定义动画效果,代码简洁易读
  • 功能丰富:支持多种动画参数和曲线类型,可以实现各种复杂的动画效果
  • 性能优秀:鸿蒙系统对属性动画进行了优化,保证了动画的流畅性和性能

核心要点总结

  1. **属性动画的核心**是“驱动可动画属性平滑过渡”,需先区分可动画属性与不可动画属性,避免无效动画配置。

  2. 三种核心动画接口(animation、animateTo、keyframeAnimateTo)各有适配场景,需根据“是否需要统一参数”“是否需要分段动画”灵活选择。

  3. 动画参数(尤其是曲线)的选择是关键,需结合场景贴合真实物理规律,让动画更自然。

  4. 实战开发中,需兼顾动画效果与性能,通过选择低开销属性、避免过度动画、适配系统场景等策略,保证动画流畅稳定。

属性动画并非孤立存在,在实际开发中,可与转场动画、粒子动画等结合使用,实现更复杂的动画效果。希望通过本文的讲解,开发者能够全面掌握鸿蒙属性动画的开发技巧,将其灵活运用到自身项目中,打造出既美观又实用、既流畅又高效的鸿蒙应用,为用户提供更优质的交互体验。

动画效果欢迎下载应用体验: 喵屿下载链接

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐