ArkUI转场动画详解(附带实例)
转场动画是指对将要出现和消失的组件做动画,对始终出现的组件应使用属性动画。
转场动画主要为了让开发者从繁重的消失节点管理中解放出来,因为如果用属性动画做组件转场,开发者需要在动画结束后的回调函数中删除组件节点;同时由于动画结束前已经删除的组件节点可能会重复出现,因此还需要在结束回调函数中增加对节点状态的判断。
创建 TransitionEffect 的代码如下:
将转场效果通过 transition 接口设置到组件,代码如下:
新增或者删除组件触发转场,代码如下:
完整的示例代码如下:
初始显示效果如下图所示:

图 1 初始显示效果
点击 Click 按钮后,红色方块以 springMotion 的方式旋转,同时颜色渐变到最终的位置,如下图所示:

图 2 第一次点击 Click 按钮的效果
再次点击 Click 按钮,红色方块逆向消失,如下图所示:

图 3 再次点击 Click 按钮的效果
下面使用 bindMenu 实现菜单弹出效果。bindMenu 为组件绑定弹出式菜单,通过点击触发。完整代码如下:

图 4 初始显示效果
点击 click 按钮之后显示的动画效果如下图所示:

图 5 点击 click 按钮之后显示的动画效果
再次点击 click 按钮之后显示的动画效果如下图所示:

图 6 再次点击 click 按钮之后显示的动画效果
转场动画主要为了让开发者从繁重的消失节点管理中解放出来,因为如果用属性动画做组件转场,开发者需要在动画结束后的回调函数中删除组件节点;同时由于动画结束前已经删除的组件节点可能会重复出现,因此还需要在结束回调函数中增加对节点状态的判断。
转场动画的分类
转场动画分为基础转场和高级模板化转场,有如下几类:- 出现/消失转场:对新增、消失的控件实现动画效果,是通用的基础转场效果;
- 导航转场:页面的路由转场方式,对应一个界面消失,另外一个界面出现的动画效果,如设置应用一级菜单切换到二级界面;
- 模态转场:新的界面覆盖在旧的界面之上的动画,旧的界面不消失,新的界面出现,如弹框就是典型的模态转场动画;
- 共享元素转场:共享元素转场又称为一镜到底,是一种界面切换时对相同或者相似的元素做的一种位置和大小匹配的过渡动画效果;
- 页面转场动画:不推荐。页面的路由转场方式,可以通过在 pageTransition 函数中自定义页面入场和页面退场的转场动效。为了实现更好的转场效果,推荐使用导航转场和模态转场;
- 旋转屏动画增强:在原旋转屏动画基础上,可配置渐隐和渐现的转场效果。
出现/消失转场动画
transition 是基础的组件转场接口,用于实现组件出现或消失的动画效果。可以通过与 TransitionEffect 对象的组合使用,定义各式效果,如下表所示:转场效果 | 说 明 | 动 画 |
---|---|---|
IDENTITY | 禁用转场效果 | 无 |
OPACITY | 默认的转场效果,透明度转场 | 出现时透明度从 0 到 1,消失时透明度从 1 到 0 |
SLIDE | 滑动转场效果 | 出现时从窗口左侧滑入,消失时从窗口右侧滑出 |
translate | 通过设置组件平移创建转场效果 | 出现时为 translate 接口设置的值到默认值 0;消失时为默认值 0 到 translate 接口设置的值 |
rotate | 通过设置组件旋转创建转场效果 | 出现时为 rotate 接口设置的值到默认值 0;消失时为默认值 0 到 rotate 接口设置的值 |
opacity | 通过设置透明度参数创建转场效果 | 出现时为 opacity 设置的值到默认透明度 1;消失时为默认透明度 1 到 opacity 设置的值 |
move | 通过 TransitionEdge 创建从窗口哪条边缘出来的效果 | 出现时从 TransitionEdge 方向滑入,消失时滑出到 TransitionEdge 方向 |
asymmetric |
通过此方法组合非对称的出现/消失转场效果
|
出现时采用 appear 设置的 TransitionEffect 出现效果,消失时采用 disappear 设置的 TransitionEffect 消失效果。 |
combine | 组合其他 TransitionEffect | 组合其他 TransitionEffect,一起生效 |
animation |
定义转场效果的动画参数:
|
调用顺序时从上往下,上面 TransitionEffect 的 animation 也会作用到下面 TransitionEffect |
创建 TransitionEffect 的代码如下:
// 出现时会是所有出现转场效果的叠加,消失时会是所有消失转场效果的叠加 // 用于说明各个 effect 跟随的动画参数 private effect: object = TransitionEffect.OPACITY // 创建了透明度转场效果,这里没有调用 animation 接口,会跟随 animateTo 的动画参数 // 通过 combine 方法,添加缩放转场效果,并指定 springMotion(0.6, 1.2) 曲线 .combine(TransitionEffect.scale({ x: 0, y: 0 }).animation({ curve: curves.springMotion(0.6, 1.2) })) // 添加旋转转场效果,这里的动画参数会跟随上面的 TransitionEffect,也就是 springMotion(0.6, 1.2) .combine(TransitionEffect.rotate({ angle: 90 })) // 添加平移转场效果,动画参数会跟随其之上带 animation 的 TransitionEffect,也就是 springMotion(0.6, 1.2) .combine(TransitionEffect.translate({ x: 150, y: 150 })) // 添加 move 转场效果,并指定 springMotion 曲线 .combine(TransitionEffect.move(TransitionEdge.END).animation({ curve: curves.springMotion() })) // 添加非对称的转场效果,由于这里没有设置 animation,因此会跟随上面的 TransitionEffect 的 animation 效果,也就是 springMotion .combine(TransitionEffect.asymmetric( TransitionEffect.scale({ x: 0, y: 0 }), TransitionEffect.rotate({ angle: 90 }) ));
将转场效果通过 transition 接口设置到组件,代码如下:
Text('test') .transition(this.effect)
新增或者删除组件触发转场,代码如下:
@State isPresent: boolean = true; ... if (this.isPresent) { Text('test') .transition(this.effect)} ... // 控制新增或者删除组件 // 方式一:将控制变量放到animateTo闭包内,未通过animation接口定义动画参数的TransitionEffect将 跟随animateTo的动画参数 this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => { this.isPresent = false; }) // 方式二:直接删除或者新增组件,动画参数由TransitionEffect的animation接口配置 this.isPresent = false;
完整的示例代码如下:
import { curves } from '@kit.ArkUI'; @Entry @Component struct TransitionEffectDemo { /* 第一步:创建 TransitionEffect */ // 创建默认透明度转场效果,并指定 springMotion(0.6, 0.8) 曲线 private effect: TransitionEffect = TransitionEffect.OPACITY .animation({ curve: curves.springMotion(0.6, 0.8) }) // 通过 combine 方法添加缩放转场;动画参数跟随上面的 springMotion(0.6, 0.8) .combine(TransitionEffect.scale({ x: 0, y: 0 })) // 添加旋转转场;动画参数同样跟随已带 animation 的前序 effect .combine(TransitionEffect.rotate({ angle: 90 })) // 添加平移转场;单独指定 springMotion() .combine( TransitionEffect.translate({ y: 150 }) .animation({ curve: curves.springMotion() }) ) // 添加 move 转场;动画参数继续跟随最近带 animation 的 effect .combine(TransitionEffect.move(TransitionEdge.END)); // 控制组件是否存在的开关 @State isPresent: boolean = false; build() { Stack() { if (this.isPresent) { /* 第二步:将转场效果通过 transition 接口设置到组件 */ Column() { Text('ArkUI') .fontWeight(FontWeight.Bold) .fontSize(20) .fontColor(Color.White) .justifyContent(FlexAlign.Center) .width(150) .height(150) .borderRadius(10) .backgroundColor(0xf56c6c) .transition(this.effect); // 应用转场效果 } // 边框装饰 Column() .width(155) .height(155) .border({ width: 5, radius: 10, color: Color.Black }); } /* 第三步:通过新增/删除组件触发转场 */ Button('click') .margin({ top: 320 }) .onClick(() => { this.isPresent = !this.isPresent; }); } .width('100%') .height('60%'); } }示例代码中采用直接删除或新增组件的方式触发转场,也可以替换为在 animateTo 闭包内通过改变控制变量来触发转场。
初始显示效果如下图所示:

图 1 初始显示效果
点击 Click 按钮后,红色方块以 springMotion 的方式旋转,同时颜色渐变到最终的位置,如下图所示:

图 2 第一次点击 Click 按钮的效果
再次点击 Click 按钮,红色方块逆向消失,如下图所示:

图 3 再次点击 Click 按钮的效果
下面使用 bindMenu 实现菜单弹出效果。bindMenu 为组件绑定弹出式菜单,通过点击触发。完整代码如下:
// 菜单按钮数据模型 class BMD { value: ResourceStr = ''; action: () => void = () => {}; } @Entry @Component struct BindMenuDemo { /* 第一步:定义一组数据用来表示菜单按钮项 */ @State items: BMD[] = [ { value: '菜单项1', action: () => { console.info('handle Menu1 select'); } }, { value: '菜单项2', action: () => { console.info('handle Menu2 select'); } } ]; build() { Column() { Button('click') .backgroundColor(0x409eff) .borderRadius(5) /* 第二步:通过 bindMenu 接口将菜单数据绑定给元素 */ .bindMenu(this.items) .justifyContent(FlexAlign.Center) .width('100%') .height(43); } } }初始显示效果如下图所示:

图 4 初始显示效果
点击 click 按钮之后显示的动画效果如下图所示:

图 5 点击 click 按钮之后显示的动画效果
再次点击 click 按钮之后显示的动画效果如下图所示:

图 6 再次点击 click 按钮之后显示的动画效果