HarmonyOS应用开发实战:小事记 - 页面转场动画:transition 组件转场与 animateTo 显式动画实现

页面预览

前言

页面转场动画是提升应用交互体验的关键手段。HarmonyOS 提供了两种动画机制:transition(组件转场动画)和 animateTo(显式动画)。两者的适用场景和实现方式不同,但可以配合使用来实现流畅的页面切换效果。本文以小事记(xiaoshiji_ohos_app) 的 EventDetailPage.ets 为分析对象,深入解析页面转场动画的实现。

本文参考 HarmonyOS 官方文档:arkts-transition-overview.mdarkts-animation-transition.md

一、transition 组件转场动画

1.1 transition 的基本用法

transition 用于组件出现和消失时的动画效果:

// transition 的基本用法
@Entry
@Component
struct EventDetailPage {
  @State isVisible: boolean = false;

  build() {
    Column() {
      if (this.isVisible) {
        Text('事件详情')
          .transition(TransitionEffect.OPACITY)  // 透明度过渡
          .transition(TransitionEffect.SLIDE)     // 滑动过渡
      }
    }
    .onClick(() => {
      this.isVisible = !this.isVisible;
    })
  }
}

1.2 TransitionEffect 类型

类型说明适用场景
OPACITY透明度过渡淡入淡出效果
SLIDE滑动过渡页面从边缘滑入
SCALE缩放过渡放大/缩小效果
MOVE移动过渡指定方向的移动
ROTATE旋转过渡旋转效果

1.3 组合使用

// 组合使用多种过渡效果
this.cardTransition = TransitionEffect.OPACITY
  .combine(TransitionEffect.SLIDE)
  .combine(TransitionEffect.SCALE);

二、animateTo 显式动画

2.1 animateTo 的基本用法

// animateTo 显式动画
import { animateTo } from '@kit.ArkUI';

@Entry
@Component
struct MemoryVideoPage {
  @State isPlaying: boolean = false;
  @State currentProgress: number = 0;

  @Builder
  buildPlayButton() {
    Circle()
      .width(72)
      .height(72)
      .fill('#FFFFFF30')
      .border({ width: 2, color: Color.White })
    Text('▶')
      .fontSize(28)
      .fontColor(Color.White)
      .margin({ top: -52 })
      .onClick(() => {
        animateTo({ duration: 300, curve: Curve.EaseInOut }, () => {
          this.isPlaying = !this.isPlaying;
        });
      })
  }
}

2.2 animateTo 的配置参数

参数类型说明默认值
durationnumber动画持续时长(ms)300
curveCurve动画曲线Curve.Ease
delaynumber延迟执行时间(ms)0
iterationsnumber动画重复次数1
onFinish() => void动画完成回调

三、页面转场动画的完整实现

3.1 列表页到详情页的转场

// 首页事件卡片的点击转场
@Entry
@Component
struct HomePage {
  private stack: NavPathStack = new NavPathStack();

  @Builder
  buildEventItem(event: LifeEvent) {
    Column() {
      Text(event.title)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
      Text(event.content)
        .fontSize(13)
        .fontColor('#6B7280')
    }
    .padding(12)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .onClick(() => {
      // 使用 animateTo 添加转场动画
      animateTo({ duration: 300, curve: Curve.EaseInOut }, () => {
        this.stack.pushPathByName('EventDetailPage', { event });
      });
    })
  }
}

3.2 详情页的进入动画

// EventDetailPage.ets — 页面进入动画
@Entry
@Component
struct EventDetailPage {
  @State isContentVisible: boolean = false;

  aboutToAppear(): void {
    // 延迟显示内容,实现逐层进入效果
    setTimeout(() => {
      animateTo({ duration: 400, curve: Curve.EaseOut }, () => {
        this.isContentVisible = true;
      });
    }, 100);
  }

  build() {
    Scroll() {
      Column() {
        // 顶部渐变区域
        Column()
          .width('100%')
          .height(240)
          .linearGradient({ angle: 135, colors: [['#7B68EE', 0.0], ['#DDA0DD', 1.0]] })
          .borderRadius({ bottomLeft: 20, bottomRight: 20 })
          .transition(TransitionEffect.OPACITY)  // 透明度过渡

        // 内容区域
        if (this.isContentVisible) {
          Column() {
            Text(this.event.title)
              .fontSize(22)
              .fontWeight(FontWeight.Bold)

            Text(this.event.content)
              .fontSize(15)
              .fontColor('#6B7280')
          }
          .transition(TransitionEffect.OPACITY
            .combine(TransitionEffect.SLIDE))
        }
      }
    }
  }
}

四、动画曲线

4.1 内置动画曲线

曲线说明适用场景
Curve.Linear线性匀速运动
Curve.Ease缓入缓出默认,适用于大多数场景
Curve.EaseIn缓入加速进入
Curve.EaseOut缓出减速退出
Curve.EaseInOut缓入缓出平滑过渡
Curve.FastOutSlowIn快入慢出自然感

4.2 自定义贝塞尔曲线

// 自定义动画曲线
import { Curve } from '@kit.ArkUI';

const customCurve = Curve.cubicBezier(0.42, 0.0, 0.58, 1.0);

animateTo({ duration: 300, curve: customCurve }, () => {
  this.isVisible = true;
});

五、常见问题

5.1 动画不执行

问题transitionanimateTo 没有生效。

可能原因

  1. 状态变量未使用 @State 装饰
  2. 动画参数配置错误
  3. 组件未正确包裹在条件渲染中
// ✅ 正确:状态变量必须使用 @State
@State isVisible: boolean = false;

// ❌ 错误:普通变量不会触发动画
isVisible: boolean = false;

5.2 动画卡顿

问题:动画执行时出现卡顿。

解决方案

  1. 减少动画的复杂度
  2. 使用 scale 替代 width/height 动画
  3. 避免在动画中触发布局变化

八、拓展阅读

本节汇总了与本文主题相关的扩展阅读材料,帮助读者深入理解相关技术细节。

8.1 官方文档

8.2 相关技术文章

  • 性能优化最佳实践
  • 常见问题排查指南

8.3 社区资源

十、最佳实践与优化建议

在实际开发中,合理运用上述技术可以显著提升应用的性能和用户体验。以下是几个关键的最佳实践建议:

10.1 性能优化要点

优化方向具体措施预期效果
渲染性能减少不必要的组件重建提升帧率
内存管理及时释放不再使用的资源降低内存占用
响应速度避免在主线程执行耗时操作提升交互流畅度

10.2 推荐实践步骤

按照以下步骤进行优化:

  1. 使用 DevEco Studio 的 Profiler 工具分析当前性能瓶颈
  2. 针对识别出的热点进行针对性优化
  3. 通过单元测试和集成测试验证优化效果
  4. 在真机环境下进行回归测试

10.3 代码示例

// 推荐的最佳实践示例
@Component
export struct OptimizedComponent {
  // 使用 @State 管理最小粒度的状态
  @State private isActive: boolean = false;

  build() {
    Column() {
      Text(this.isActive ? '激活' : '未激活')
        .fontSize(16)
    }
    .onClick(() => {
      // 使用 animateTo 实现平滑过渡
      animateTo({ duration: 300 }, () => {
        this.isActive = !this.isActive;
      });
    });
  }
}

最佳实践提示:在编写代码时,始终遵循 ArkUI 的性能优化原则,避免在 build() 方法中执行复杂计算或频繁的状态更新。

总结

本文深入解析了页面转场动画的实现。核心要点如下:

  1. transition 组件转场:适用于组件出现和消失的场景,支持 OPACITYSLIDESCALE 等效果
  2. animateTo 显式动画:适用于状态变化驱动的动画,支持 durationcurvedelay 等参数配置
  3. 动画曲线:内置多种曲线,支持自定义贝塞尔曲线
  4. 组合动画transitionanimateTo 可以配合使用,实现丰富的转场效果

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


九、完整示例代码

9.1 完整组件实现

以下是一个完整的组件实现示例,展示了本文介绍的各个技术点的综合运用:

import { Component, State, Prop } from '@kit.ArkUI';

@Component
export struct DemoComponent {
  @Prop title: string = '';
  @State count: number = 0;

  build() {
    Column({ space: 12 }) {
      // 标题区域
      Text(this.title)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#1A1A2E')
        .width('100%')

      // 内容区域
      Text(`当前计数: ${this.count}`)
        .fontSize(14)
        .fontColor('#6B7280')

      // 交互按钮
      Button('点击增加')
        .width(120)
        .height(40)
        .backgroundColor('#7B68EE')
        .borderRadius(20)
        .fontColor(Color.White)
        .onClick(() => {
          this.count++;
        })
    }
    .width('100%')
    .padding(16)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .shadow({ radius: 4, color: '#00000008', offsetX: 0, offsetY: 2 })
  }
}

9.2 使用方式

在页面中引入并使用该组件:

@Entry
@Component
struct Index {
  build() {
    Column() {
      DemoComponent({ title: '示例组件' })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8F9FA')
  }
}

9.3 代码说明

  • 组件封装:使用 @Component 装饰器定义可复用的组件
  • 状态管理:使用 @State 管理组件内部状态
  • 参数传递:使用 @Prop 接收外部传入的参数
  • 事件处理:使用 onClick 处理用户交互
  • 样式优化:使用 borderRadiusshadow 等属性美化 UI

相关资源:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少湖说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值