首页 > 编程笔记 > 通用技能 阅读:2

ArkUI转场动画详解(附带实例)

转场动画是指对将要出现和消失的组件做动画,对始终出现的组件应使用属性动画。

转场动画主要为了让开发者从繁重的消失节点管理中解放出来,因为如果用属性动画做组件转场,开发者需要在动画结束后的回调函数中删除组件节点;同时由于动画结束前已经删除的组件节点可能会重复出现,因此还需要在结束回调函数中增加对节点状态的判断。

转场动画的分类

转场动画分为基础转场和高级模板化转场,有如下几类:

出现/消失转场动画

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:出现转场的效果
  • disappear:消失转场的效果
出现时采用 appear 设置的 TransitionEffect 出现效果,消失时采用 disappear 设置的 TransitionEffect 消失效果。
combine 组合其他 TransitionEffect 组合其他 TransitionEffect,一起生效
animation 定义转场效果的动画参数:
  • 如果不定义,会跟随 animateTo 的动画参数
  • 不支持通过控件的 animation 接口配置动画参数
  • TransitionEffect 中 animation 的 onFinish 不生效
调用顺序时从上往下,上面 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 按钮之后显示的动画效果

相关文章