ArkUI 转场动画:组件出现、消失与页面切换的过渡

转场是"出现"和"消失"的动画

属性动画管的是"值怎么变",转场动画管的是"组件怎么出现、怎么消失"。元素插入界面、删除界面、页面之间切换,都需要转场来避免生硬的瞬间跳变。

ArkUI 的转场分两类:组件转场(组件出现和消失)和页面转场(页面之间切换)。

组件转场:transition

transition 定义组件插入和移除时的过渡效果:

@Entry
@Component
struct TransitionDemo {
  @State show: boolean = false;

  build() {
    Column({ space: 20 }) {
      Button('显示/隐藏')
        .onClick(() => {
          this.show = !this.show;
        })

      // 条件渲染的组件,出现和消失带转场
      if (this.show) {
        Text('我出现了')
          .fontSize(24)
          .transition(
            TransitionEffect.OPACITY  // 淡入淡出
              .animation({ duration: 500, curve: Curve.EaseInOut })
          )
      }
    }
  }
}

TransitionEffect 提供多种效果,可以组合:

效果作用
TransitionEffect.OPACITY淡入淡出
TransitionEffect.SLIDE滑动进入退出
TransitionEffect.translate({})平移(指定方向)
TransitionEffect.scale({})缩放
TransitionEffect.rotate({})旋转
.combine()组合多种效果
.asymmetric()进入和退出用不同效果

组合转场效果

多个效果用 .combine() 串联:

if (this.show) {
  Text('复合转场')
    .transition(
      TransitionEffect.OPACITY
        .combine(TransitionEffect.translate({ x: 200 }))  // 淡入 + 从右滑入
        .animation({ duration: 300, curve: Curve.EaseInOut })
    )
}

这个组件出现时"淡入 + 从右侧滑入",消失时反向。

进入和退出用不同效果

asymmetric 让进入动画和退出动画不一样:

if (this.show) {
  Text('非对称转场')
    .transition(
      TransitionEffect.OPACITY
        .asymmetric(
          // 进入:淡入 + 从右滑入
          TransitionEffect.OPACITY.combine(TransitionEffect.translate({ x: 200 })),
          // 退出:淡出 + 向左滑出
          TransitionEffect.OPACITY.combine(TransitionEffect.translate({ x: -200 }))
        )
        .animation({ duration: 300 })
    )
}

进入从右滑入,退出向左滑出,模拟"进栈"和"出栈"的方向感。

页面转场:Navigation 的 transition

页面之间切换也有转场。NavigationNavDestination 支持页面转场:

@Component
struct DetailPage {
  build() {
    NavDestination() {
      Text('详情页')
    }
    // 页面转场:默认滑动 + 淡入
    .transition(
      TransitionEffect.translate({ x: '100%' })
        .combine(TransitionEffect.OPACITY)
    )
  }
}

页面切换的默认转场是水平滑动 + 淡入淡出。可以自定义,但要注意:页面级的转场过重会影响导航流畅度。

弹窗式提示的转场

一个常见的"加载成功提示":淡入出现,停留,淡出消失。

@Entry
@Component
struct ToastDemo {
  @State showToast: boolean = false;
  @State toastMsg: string = '';

  build() {
    Stack({ alignContent: Alignment.Center }) {
      Column({ space: 20 }) {
        Button('显示提示')
          .onClick(() => {
            this.toastMsg = '操作成功';
            this.showToast = true;
            // 2 秒后自动隐藏
            setTimeout(() => {
              this.showToast = false;
            }, 2000);
          })
      }

      // 提示浮层:淡入淡出
      if (this.showToast) {
        Text(this.toastMsg)
          .fontColor(Color.White)
          .backgroundColor('#80000000')
          .padding(16)
          .borderRadius(8)
          .transition(
            TransitionEffect.OPACITY
              .combine(TransitionEffect.scale({ x: 0.8, y: 0.8 }))  // 淡入 + 缩放
              .animation({ duration: 200 })
          )
      }
    }
  }
}

这个提示出现时淡入 + 从 0.8 倍放大到 1 倍,消失时反向,配合 200ms 的短时长,轻量不突兀。

转场动画的小经验

  1. 转场要短。组件出现消失的转场 200-300ms 合适,页面转场可以稍长到 300-400ms。转场太慢会让用户感觉操作延迟。

  2. 进入退出方向要有逻辑。列表项新增从顶部滑入、删除向左侧滑出,符合用户的直觉预期。方向乱来会让人困惑。

  3. 条件渲染才触发转场if 条件渲染的组件,条件从 false 到 true 触发进入转场,true 到 false 触发退出转场。如果用 visibility 隐藏,不会触发退出转场,这点要区分。

  4. 别滥用转场。不是每个元素出现都要转场,重要提示、弹窗、页面切换加转场能提升体验,普通列表渲染加转场反而累赘。

  5. 转场和状态要配合。转场动画触发的前提是状态变化(if 条件),确保 @State 切换正确,转场才会按预期执行。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐