news 2026/10/23 22:03:55

【ArkUI 练中学】第7课:动画体系

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【ArkUI 练中学】第7课:动画体系

本节目标

· 理解 ArkUI 动画体系的基本分类:属性动画、显式动画、转场动画、路径动画
· 掌握 animateTo 显式动画接口的用法,理解其闭包驱动机制与适用场景
· 掌握 .animation() 属性动画接口的用法,理解其声明式自动触发机制
· 区分 animateTo 与 .animation() 的核心差异,能够根据场景正确选型
· 掌握 transition 组件内转场动画的用法,理解组件插入/删除时的动效配置
· 掌握 pageTransition 页面转场动画的用法,理解 RouteType 对入场退场动画的控制
· 掌握 motionPath 路径动画的用法,能够配合 animateTo 实现自定义路径位移动画
· 了解 Curve 动画曲线的种类与选型,掌握 AnimateParam 核心参数的配置
· 了解 keyframeAnimateTo 关键帧动画的基本概念
· 能够独立为组件添加流畅的动画效果,并遵循动画性能优化最佳实践

一、动画体系概述

1.1 动画的分类

在 ArkUI 中,动画可以分为以下几种常见类型:位置动画用于控制控件的移动位置,缩放动画通过调整控件的缩放比例实现元素的放大或缩小,透明度动画通过调整控件的透明度实现渐显或渐隐的效果,旋转动画使控件围绕某一轴心旋转。这些动画效果可以单独使用,也可以组合使用,创造出多样的动态交互效果。

从接口层面来看,ArkUI 提供了多种动画能力:

· 属性动画:通过可动画属性改变引起 UI 上产生的连续视觉效果,ArkUI 提供三种动画接口 animateTo、animation 和 keyframeAnimateTo 驱动组件属性按照动画曲线等动画参数进行连续的变化,产生属性动画。
· 转场动画:包括组件内转场(transition)和页面间转场(pageTransition),用于组件插入/删除或页面切换时的过渡效果。
· 路径动画:motionPath 用于设置组件进行位移动画时的运动路径。

1.2 动画的构成要素

一个完整的动画通常包含以下要素:

· 触发方式:动画由什么条件触发(状态变化、用户交互、组件插入/删除等)
· 动画参数:包括时长(duration)、动画曲线(curve)、延迟(delay)、播放模式(playMode)、播放次数(iterations)等
· 动画属性:参与动画变化的组件属性,如 width、height、opacity、scale、rotate、translate 等

支持的属性包括 width、height、backgroundColor、opacity、scale、rotate、translate 等。

二、animateTo 显式动画

2.1 基本用法

animateTo 是全局显式动画接口,用于指定由于闭包代码导致的状态变化插入过渡动效。其接口签名为:

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

其中 value 指定 AnimateParam 对象(包括时长、曲线等),event 为动画的闭包函数,闭包内变量改变产生的属性动画将遵循相同的动画参数。

@Entry@Componentstruct AnimateToExample{@StatewidthSize:number=100@StateheightSize:number=100@StaterotateAngle:number=0build(){Column({space:20}){Button('改变尺寸').width(this.widthSize).height(this.heightSize).backgroundColor('#007DFF').onClick(()=>{this.getUIContext()?.animateTo({duration:1000,curve:Curve.EaseOut},()=>{this.widthSize=200this.heightSize=200})})Button('旋转').rotate({angle:this.rotateAngle}).onClick(()=>{this.getUIContext()?.animateTo({duration:800,curve:Curve.FastOutSlowIn},()=>{this.rotateAngle=this.rotateAngle+90})})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}

注意:直接使用 animateTo 可能导致 UI 上下文不明确的问题,建议使用 getUIContext() 获取 UIContext 实例,并使用绑定实例的 animateTo 调用。

2.2 适用场景

animateTo 是一个通用函数,对闭包前界面和闭包中的状态变量引起的界面之间的差异做动画,支持多次调用,支持嵌套。适用于对多个可动画属性配置相同动画参数的场景,或命令式显式触发动画的场景,以及需要嵌套使用动画的场景。

2.3 AnimateParam 核心参数

AnimateParam 对象用于配置动画的各项参数,常用的包括:

· duration:动画持续时间,单位为毫秒,默认值 1000。
· curve:动画曲线,默认值 Curve.EaseInOut。
· delay:动画延迟时间,单位为毫秒,默认值 0。
· iterations:动画播放次数,默认值 1,设置为 -1 表示无限次。
· playMode:动画播放模式,默认值 PlayMode.Normal。
· onFinish:动画播放完成回调。

三、animation 属性动画

3.1 基本用法

.animation() 是属性动画接口,与 animateTo 需要将属性修改封装在闭包中执行不同,animation 接口无需使用闭包,只需将其加在要做动画的可动画属性后即可。animation 只要检测到其绑定的可动画属性发生变化,就会自动添加属性动画。

@Entry@Componentstruct AnimationExample{@StatewidthSize:number=100@StateopacityValue:number=1.0build(){Column({space:20}){Row().width(this.widthSize).height(60).backgroundColor('#007DFF').animation({duration:1000,curve:Curve.EaseOut})Row().width(60).height(60).backgroundColor('#FF5500').opacity(this.opacityValue).animation({duration:800,curve:Curve.Linear})Button('触发动画').onClick(()=>{this.widthSize=this.widthSize===100?250:100this.opacityValue=this.opacityValue===1.0?0.3:1.0})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}

关键规则:属性动画只对写在 animation 前面的属性生效,且对组件构造器的属性不生效。组件接口调用从下往上执行,animation 只会作用于在其之上调用的属性,组件可以根据调用顺序对多个属性设置不同的 animation。

3.2 适用场景

animation 是声明式属性动画,适用于对不同可动画属性配置不同参数动画的场景,以及希望属性改变时隐式触发动画的声明式写法。

3.3 与 animateTo 的区别

两者的核心差异在于触发方式和作用范围:

· 触发方式:animation 由属性变化自动触发,是声明式的;animateTo 需要手动调用接口,是命令式的。
· 作用范围:animateTo 对闭包内所有属性变化统一用一套动画参数;animation 根据调用顺序对多个属性可设置不同参数。
· 打断方式:animateTo 可以用 duration: 0 的方式干净打断;animation 没有直接的打断接口。
· 选型建议:animateTo 适合“按条件决定是否加动画”或需要精细控制的场景;.animation() 适合属性一变就自动触发动画的声明式场景。

绝对不要对同一个属性同时使用两者,否则会导致动画叠加、闪烁、跳动。

四、transition 组件内转场

4.1 基本用法

组件内转场主要通过 transition 属性配置转场参数,在组件插入和删除时显示过渡动效,主要用于容器组件中的子组件插入和删除时,提升用户体验。

当前有两种方式触发组件的 transition:当组件插入或删除时(如 if 条件改变、ForEach 新增删除组件),会递归地触发所有新插入/删除的组件的 transition 效果;当组件 Visibility 属性在可见和不可见之间改变时,只触发该组件的 transition 效果。

@Entry@Componentstruct TransitionExample{@StateisShow:boolean=truebuild(){Column({space:20}){Button('切换显示').onClick(()=>{this.getUIContext()?.animateTo({duration:500,curve:Curve.EaseInOut},()=>{this.isShow=!this.isShow})})if(this.isShow){Row().width(200).height(100).backgroundColor('#007DFF').transition({type:TransitionType.Insert,opacity:0,translate:{x:-200,y:0}})}}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}

4.2 TransitionEffect 新接口

从 API 10 开始,transition 支持 TransitionEffect 对象,以函数的形式指定转场效果,使用更加灵活:

Row().transition(TransitionEffect.OPACITY.combine(TransitionEffect.translate({x:-200})).animation({duration:500,curve:Curve.EaseOut}))

TransitionEffect 提供了 OPACITY、translate、scale、rotate、move、asymmetric 等预定义效果,并支持通过 combine 组合多种效果。

4.3 与 animateTo 的配合

transition 必须和 animateTo 一起使用才能产生组件转场效果。transition 和 animateTo 作用在不同层面,但对同一属性(如 opacity、scale)同时生效时会产生叠加。组件显隐用 transition,属性变化用 animateTo,两者各司其职,不要对同一属性重复设动画。

五、pageTransition 页面转场

5.1 基本用法

两个页面间发生跳转时,可以配置各自页面的页面转场参数实现自定义的页面转场效果。页面间转场效果写在 pageTransition 函数中,通过 PageTransitionEnter 和 PageTransitionExit 指定页面进入和退出的动画效果。

// 页面 ApageTransition(){PageTransitionEnter({type:RouteType.Push,duration:500}).slide(SlideEffect.Right)PageTransitionExit({type:RouteType.Push,duration:500}).slide(SlideEffect.Left)}

5.2 RouteType 类型

type 参数用于区分页面转场的类型:

· RouteType.None(默认值):对页面栈的 push、pop 操作均生效。
· RouteType.Push:仅在页面入栈(pushUrl)时生效。
· RouteType.Pop:仅在页面出栈(back / pop)时生效。

以 push 操作为例:通过 pushUrl 从页面 A 跳转到页面 B,则页面 A 退出做退场动画,页面 B 进入做入场动画。通过 back 从页面 B 返回到页面 A,则页面 B 退出做退场动画,页面 A 进入做入场动画。

5.3 可配置的转场效果

可通过 slide、translate、scale、opacity 属性定义不同的页面转场效果。对于 PageTransitionEnter 而言,这些效果表示入场时的起点值;对于 PageTransitionExit 而言,这些效果表示退场的终点值。

六、motionPath 路径动画

6.1 基本用法

motionPath 用于设置组件进行位移动画时的运动路径。其参数 MotionPathOptions 包含以下字段:

· path:位移动画的运动路径,使用 SVG 路径字符串。path 中支持使用 start 和 end 进行起点和终点的替代,如 ‘Mstart.x start.y L50 50 Lend.x end.y Z’。设置为空字符串时相当于不设置路径动画。
· from:运动路径的起点,默认值 0.0,取值范围 [0, 1]。
· to:运动路径的终点,默认值 1.0,取值范围 [0, 1],且满足 to 值 >= 异常值处理后的 from 值。
· rotatable:是否跟随路径进行旋转,默认值 false。

6.2 配合 animateTo 使用

motionPath 仅配置运动路径参数,需配合 animateTo 等动画触发方法及组件属性状态变化才能产生实际的位移动画效果,单独设置 motionPath 不会触发动画。

@Entry@Componentstruct MotionPathExample{@Statetoggle:boolean=truebuild(){Column(){Button('沿路径运动').margin(50).motionPath({path:'Mstart.x start.y L300 200 L300 500 Lend.x end.y',from:0.0,to:1.0,rotatable:true}).onClick(()=>{this.getUIContext()?.animateTo({duration:4000,curve:Curve.Linear},()=>{this.toggle=!this.toggle})})}.width('100%').height('100%').alignItems(this.toggle?HorizontalAlign.Start:HorizontalAlign.Center)}}

上述示例中,组件沿自定义路径从起点移动到 (300, 200),再到 (300, 500),再到终点,同时组件跟随路径方向旋转。

七、动画曲线与关键帧动画

7.1 Curve 动画曲线

ArkUI 提供了丰富的动画曲线(Curve),用于控制动画过程中属性值随时间变化的速率。常用曲线包括:

· Linear:动画从头到尾的速度都是相同的。
· Ease:动画以低速开始,然后加快,在结束前变慢,对应 cubic-bezier(0.25, 0.1, 0.25, 1.0)。
· EaseIn:动画以低速开始,对应 cubic-bezier(0.42, 0.0, 1.0, 1.0)。
· EaseOut:动画以低速结束,对应 cubic-bezier(0.0, 0.0, 0.58, 1.0)。
· EaseInOut:动画以低速开始和结束,对应 cubic-bezier(0.42, 0.0, 0.58, 1.0)。
· FastOutSlowIn:标准曲线,对应 cubic-bezier(0.4, 0.0, 0.2, 1.0)。
· Friction:阻尼曲线,对应 cubic-bezier(0.2, 0.0, 0.2, 1.0)。

此外,@ohos.curves 模块还提供了 stepsCurve(阶梯曲线)、cubicBezierCurve(三阶贝塞尔曲线)、springMotion(弹簧曲线)等高级插值曲线构造能力。

7.2 keyframeAnimateTo 关键帧动画

keyframeAnimateTo 用于实现分段属性动画,支持多个闭包内改变属性,每一段闭包中的状态变量与前一次的差异做动画。适用于同一属性需要做连续多个动画的场景,支持多次调用,不推荐嵌套。

this.getUIContext()?.keyframeAnimateTo({delay:100},[{duration:800,curve:Curve.EaseOut,event:()=>{this.translateX=200;this.translateY=200}},{duration:600,curve:Curve.EaseIn,event:()=>{this.translateX=400;this.translateY=400}}])

八、动画性能优化

8.1 优先使用合成属性

动画优先改 translate、scale、opacity 等合成属性,避免直接动画 width、height、margin 等布局属性。动画过程中尽量避免触发不必要的布局调整和重绘操作。

// ✅ 推荐:使用 translate 实现移动this.getUIContext()?.animateTo({duration:300,curve:Curve.EaseOut},()=>{this.translateX=100})// ❌ 不推荐:直接动画 width/margin 等布局属性// this.getUIContext()?.animateTo({ duration: 300 }, () => {// this.widthValue = 200// })

8.2 合并动画调用

多个动画合并参数时,使用同一个 animateTo 而不是各自调一次,减少状态刷新次数。

8.3 缩小状态影响范围

缩小状态影响范围,避免在动画中创建新对象或频繁 setState 整页刷新。

8.4 使用合适的帧率

在大多数情况下,动画的帧率保持在 60 FPS(帧每秒)是最理想的,这能保证动画的流畅性。

8.5 避免在生命周期中调用动画

不推荐在 aboutToAppear、aboutToDisappear 中调用动画。在 aboutToAppear 中调用动画时,自定义组件内的 build 还未执行,内部组件还未创建,动画时机过早,动画属性没有初值无法对组件产生动画。执行 aboutToDisappear 时,组件即将销毁,不能在 aboutToDisappear 里面做动画。

九、多元化习题

习题 1(判断题)

题目:在 ArkUI 中,.animation() 属性动画接口需要将属性修改封装在闭包中执行,而 animateTo 接口无需使用闭包。

答案:错误

解读:题目描述正好相反。animateTo 接口需要将属性修改封装在闭包中执行,闭包内变量改变产生的属性动画将遵循相同的动画参数。.animation() 接口无需使用闭包,只需将其加在要做动画的可动画属性后即可,只要检测到其绑定的可动画属性发生变化,就会自动添加属性动画。

习题 2(单选题)

题目:以下关于 animateTo 和 .animation() 的说法,正确的是( )

A. animateTo 由属性变化自动触发,是声明式的
B. .animation() 需要手动调用接口触发动画
C. .animation() 只对写在它前面的属性生效
D. animateTo 和 .animation() 可以同时作用于同一个属性而不产生冲突

答案:C

解读:animateTo 需要手动调用接口,是命令式的;.animation() 由属性变化自动触发,是声明式的,选项 A、B 错误。.animation() 只对写在它前面的属性生效,选项 C 正确。绝对不要对同一个属性同时使用两者,会导致动画叠加、闪烁、跳动,选项 D 错误。

习题 3(多选题)

题目:关于 transition 组件内转场动画,以下说法正确的有(多选):

A. transition 在组件插入和删除时显示过渡动效
B. transition 必须和 animateTo 一起使用才能产生组件转场效果
C. transition 可以定义平移、透明度、旋转、缩放等转场效果
D. transition 只能通过 if 条件改变来触发

答案:A、B、C

解读:transition 在组件插入和删除时显示过渡动效,主要用于容器组件中的子组件插入和删除时,选项 A 正确。transition 必须和 animateTo 一起使用才能产生组件转场效果,选项 B 正确。transition 可以定义平移、透明度、旋转、缩放这几种转场样式的单个或者组合的转场效果,选项 C 正确。transition 可以通过组件插入/删除(如 if 条件改变、ForEach 新增删除组件)或 Visibility 属性变化触发,选项 D 错误。

习题 4(代码填空题)

题目:请补全以下代码,使用 motionPath 配合 animateTo 实现组件沿自定义路径运动。

@Entry@Componentstruct PathDemo{@Statetoggle:boolean=truebuild(){Column(){Button('沿路径运动').margin(50).______________({path:'Mstart.x start.y L300 200 L300 500 Lend.x end.y',from:0.0,to:1.0,rotatable:true}).onClick(()=>{this.getUIContext()?.animateTo({duration:4000,curve:Curve.Linear},()=>{this.toggle=!this.toggle})})}.width('100%').height('100%')}}

答案:motionPath

解读:motionPath 用于设置组件进行位移动画时的运动路径,其参数包含 path(SVG 路径字符串)、from(起点)、to(终点)、rotatable(是否跟随路径旋转)。motionPath 仅配置运动路径参数,需配合 animateTo 等动画触发方法及组件属性状态变化才能产生实际的位移动画效果。

习题 5(代码改错题)

题目:以下代码存在性能问题,请指出问题并修正。

@Entry@Componentstruct BadAnimation{@StatewidthValue:number=100@StateheightValue:number=100build(){Column(){Row().width(this.widthValue).height(this.heightValue).backgroundColor('#007DFF')Button('放大').onClick(()=>{this.getUIContext()?.animateTo({duration:500},()=>{this.widthValue=300})this.getUIContext()?.animateTo({duration:500},()=>{this.heightValue=300})})}}}

答案:该代码存在两个问题。第一,直接动画 width 和 height 等布局属性会触发布局重排,性能较差,应优先使用 translate 或 scale 等合成属性。第二,两个 animateTo 分别调用,应合并为一个 animateTo。修正如下:

@Entry@Componentstruct GoodAnimation{@StatescaleValue:number=1.0build(){Column(){Row().width(100).height(100).backgroundColor('#007DFF').scale({x:this.scaleValue,y:this.scaleValue})Button('放大').onClick(()=>{this.getUIContext()?.animateTo({duration:500,curve:Curve.EaseOut},()=>{this.scaleValue=2.0})})}}}

解读:动画优先改 translate、scale、opacity 等合成属性,少直接动画 width、height 等布局属性。多个动画合并参数时,使用同一个 animateTo 而不是各自调一次,减少状态刷新次数。

习题 6(简答题)

题目:简述 animateTo 和 .animation() 的核心区别,并说明各自的适用场景。

答案:animateTo 是全局显式动画接口,需要手动调用,将属性修改封装在闭包中执行,对闭包前界面和闭包中的状态变量引起的界面之间的差异做动画,闭包内所有属性变化统一用一套动画参数。适用于对多个可动画属性配置相同动画参数的场景,或命令式显式触发动画的场景,以及需要嵌套使用动画的场景。.animation() 是属性动画接口,声明式写法,无需使用闭包,只需将其加在要做动画的可动画属性后即可,只要检测到其绑定的可动画属性发生变化就会自动添加属性动画。适用于对不同可动画属性配置不同参数动画的场景,以及希望属性改变时隐式触发动画的声明式写法。

解读:选择哪种动画接口取决于具体场景。如果需要精确控制动画的触发时机,或需要为多个属性统一设置动画参数,使用 animateTo;如果希望属性变化时自动带有动画效果,且不同属性需要不同的动画参数,使用 .animation() 更加便捷。需要注意的是,绝对不要对同一个属性同时使用两者,会导致动画叠加。

十、本节知识点总结

动画分类
ArkUI 动画包括属性动画、转场动画和路径动画。属性动画通过可动画属性改变产生连续视觉效果,转场动画用于组件插入/删除或页面切换,路径动画用于组件沿自定义路径位移。

animateTo 显式动画
全局命令式动画接口,将属性修改封装在闭包中执行,闭包内所有属性变化统一用一套动画参数。支持嵌套使用,适用于多个属性配置相同参数的场景。

animation 属性动画
声明式属性动画接口,加在可动画属性后即可,属性变化时自动触发。只对写在它前面的属性生效,适用于不同属性配置不同参数的场景。

transition 组件内转场
通过 transition 属性在组件插入/删除时显示过渡动效,需配合 animateTo 使用。支持 TransitionEffect 对象灵活组合多种效果。

pageTransition 页面转场
通过 PageTransitionEnter 和 PageTransitionExit 配置页面进入和退出的动画效果,RouteType 控制 push / pop 场景的生效范围。

motionPath 路径动画
设置组件沿 SVG 路径进行位移动画,支持 from / to 控制路径起止位置,rotatable 控制是否跟随路径旋转,需配合 animateTo 使用。

动画曲线
Curve 提供了 Linear、Ease、EaseIn、EaseOut、EaseInOut、FastOutSlowIn 等多种曲线,@ohos.curves 模块还提供弹簧曲线等高级插值能力。

性能优化
优先使用 translate / scale / opacity 等合成属性,合并相同参数的 animateTo,缩小状态影响范围,保持 60 FPS 帧率,避免在 aboutToAppear / aboutToDisappear 中调用动画。

下节预告
第8课将深入讲解 ArkUI 中的手势交互,包括点击、长按、拖拽、捏合等基础手势的识别与处理,组合手势的使用方式,以及手势与动画的联动实现。

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

【ArkUI 练中学】第6课:状态管理进阶

本节目标理解 State 在嵌套对象场景下的局限性,掌握 Observed 与 ObjectLink 配合实现深度监听的方法掌握 Watch 装饰器监听状态变量变化的能力,理解其严格相等触发机制及使用场景掌握 AppStorage 应用级全局状态存储的读写方法,理解 S…

作者头像 李华
网站建设 2026/10/19 0:41:02

【ArkUI 练中学】第4课:高级布局与列表性能优化

本节目标掌握 Flex 弹性布局的核心属性 flexBasis、flexGrow、flexShrink 及 FlexWrap 换行布局的用法掌握 Grid 网格布局的 columnsTemplate / rowsTemplate 行列设置方法,理解 fr 单位与 GridItem 的配合掌握 Stack 层叠布局的 alignContent 对齐方式与 zIn…

作者头像 李华
网站建设 2026/10/19 6:49:42

三维模型制作01——第一周(10.9)

三维模型制作010 参考资料和备课指南1 今日整体课程安排2 认识3dsmax工作界面2.1 标题栏2.1.1 保存方式2.1.2 讲解键盘2.2 菜单栏2.3 主工具栏2.4 视图区2.5 命令面板区2.6 视图控制区2.7 状态与提示信息栏2.8 动画控制区3 将UI界面复原4 细节注意4.1 单位设置4.2 viewcube&…

作者头像 李华
网站建设 2026/10/18 0:12:27

单臂路由实验详解:VLAN间通信的配置原理与排错实战

单臂路由这个实验,算是VLAN间通信里最经典也最容易让人绕晕的一个了。很多人在模拟器里照着教程敲命令,明明每一步都做对了,两个PC就是ping不通。我刚开始学的时候也卡在这上面好几天,后来发现坑几乎都出在交换机接口的角色划分和…

作者头像 李华
网站建设 2026/10/22 23:18:50

基于Java Web的人才招聘系统设计与实现文档撰写指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 23:34:55

分治-快速排序

1.颜色划分 75. 颜色分类 - 力扣(LeetCode)https://leetcode.cn/problems/sort-colors/description/ 分治就是分而治之,把一个非常大的问题,转化为很多相似的子问题。子问题基础上继续划分,直到划分到这个子问题可…

作者头像 李华