鸿蒙技术干货11:属性动画与转场效果实战

本文聚焦基础属性动画(animateTo)和页面转场动画(transition),通过「列表项滑动删除 + 页面切换渐变」的实战案例,带大家掌握动画开发核心逻辑~

一、核心认知:动画的应用场景与核心 API

1. 应用场景

  • 组件交互反馈(如按钮点击缩放、列表项操作动画)
  • 页面切换过渡(如渐变、滑动进入)
  • 数据变化可视化(如进度条加载、数字滚动)
  • 引导用户注意力(如弹窗弹出、通知提示)

2. 核心 API

  • 属性动画:animateTo(声明式动画,无需手动控制动画帧)
  • 转场动画:transition(组件转场配置)、pageTransition(页面转场配置)
  • 关键参数:duration(时长)、curve(动画曲线)、delay(延迟执行)

二、属性动画:animateTo 基础用法

属性动画通过animateTo函数包裹组件属性修改逻辑,自动实现动画过渡,支持位置、透明度、尺寸等常见属性:

1. 基础效果示例(控制透明度、尺寸、位置)

typescript 复制代码
import { animateTo, Curve } from '@ohos.ui.animation';

@Component
struct AnimateToBasicDemo {
  @State opacity: number = 1;
  @State scale: number = 1;
  @State offsetX: number = 0;

  build() {
    Column({ space: 30 })
      .width('100%')
      .height('100%')
      .padding(30)
      .backgroundColor('#f5f5f5') {
      
      // 动画目标组件
      Text('属性动画演示')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .opacity(this.opacity)
        .scale({ x: this.scale, y: this.scale })
        .translate({ x: this.offsetX })
        .backgroundColor('#2f54eb')
        .color('#ffffff')
        .padding(20)
        .borderRadius(12)

      // 控制按钮组
      Row({ space: 20 }) {
        Button('透明度变化')
          .type(ButtonType.Capsule)
          .onClick(() => {
            animateTo({
              duration: 800, // 动画时长(毫秒)
              curve: Curve.EaseInOut // 动画曲线(缓进缓出)
            }, () => {
              this.opacity = this.opacity === 1 ? 0.3 : 1;
            });
          })

        Button('缩放效果')
          .type(ButtonType.Capsule)
          .onClick(() => {
            animateTo({ duration: 500 }, () => {
              this.scale = this.scale === 1 ? 1.2 : 1;
            });
          })

        Button('水平位移')
          .type(ButtonType.Capsule)
          .onClick(() => {
            animateTo({ duration: 1000 }, () => {
              this.offsetX = this.offsetX === 0 ? 100 : 0;
            });
          })
      }
    }
  }
}

2. 核心参数说明

  • duration:动画时长(默认 300 毫秒),数值越大动画越慢;
  • curve:动画曲线(Curve.Linear匀速、Curve.EaseIn缓入、Curve.EaseOut缓出、Curve.EaseInOut缓进缓出);
  • delay:延迟执行时间(默认 0 毫秒),可实现动画排队效果;
  • 回调函数:包裹需要动画的属性修改逻辑,属性变化会自动生成过渡动画。

三、转场动画:transition 组件用法

转场动画用于组件显示 / 隐藏、页面切换时的过渡效果,鸿蒙 5.0 + 支持通过transition直接配置,无需复杂逻辑:

1. 页面切换渐变效果

main_pages.json注册的页面中,通过pageTransition配置全局页面转场:

scss 复制代码
// pages/FirstPage.ets(首页)
@Entry
@Component
struct FirstPage {
  build() {
    Column({ space: 30 })
      .width('100%')
      .height('100%')
      .padding(30)
      .backgroundColor('#f5f5f5') {
      
      Text('首页')
        .fontSize(32)
        .fontWeight(FontWeight.Bold)

      Button('跳转到第二页')
        .type(ButtonType.Capsule)
        .width(200)
        .height(50)
        .backgroundColor('#2f54eb')
        .onClick(() => {
          router.pushUrl({ url: 'pages/SecondPage' });
        })
    }
  }

  // 页面转场配置(渐变效果)
  pageTransition() {
    PageTransition()
      .enter('fade', { duration: 800, curve: Curve.EaseInOut }) // 进入渐变
      .exit('fade', { duration: 800, curve: Curve.EaseInOut }) // 退出渐变
  }
}

// pages/SecondPage.ets(第二页)
@Entry
@Component
struct SecondPage {
  build() {
    Column({ space: 30 })
      .width('100%')
      .height('100%')
      .padding(30)
      .backgroundColor('#f5f5f5') {
      
      Text('第二页')
        .fontSize(32)
        .fontWeight(FontWeight.Bold)

      Button('返回首页')
        .type(ButtonType.Capsule)
        .width(200)
        .height(50)
        .backgroundColor('#ff4d4f')
        .onClick(() => {
          router.backUrl();
        })
    }
  }

  // 复用渐变转场配置
  pageTransition() {
    PageTransition()
      .enter('fade', { duration: 800, curve: Curve.EaseInOut })
      .exit('fade', { duration: 800, curve: Curve.EaseInOut })
  }
}

2. 组件转场(列表项滑动删除前置)

组件显示 / 隐藏时的转场效果,可结合ifvisibility控制:

less 复制代码
// 组件转场示例(渐变+位移)
Text('可隐藏组件')
  .transition([
    TransitionEffect.fade({ duration: 500 }), // 渐变
    TransitionEffect.slide({ direction: SlideDirection.Bottom, duration: 500 }) // 底部滑入滑出
  ])
  .visibility(this.isShow ? Visibility.Visible : Visibility.Hidden)

四、实战整合:列表项滑动删除 + 页面渐变

1. 列表项滑动删除(属性动画核心应用)

typescript 复制代码
import { animateTo, Curve } from '@ohos.ui.animation';
import router from '@ohos.router';

@Component
struct SlideDeleteList {
  @State taskList: string[] = ['学习属性动画', '实现转场效果', '开发滑动删除', '整合页面渐变'];
  @State deleteOffsetX: number[] = this.taskList.map(() => 0); // 每个列表项的位移

  // 滑动删除动画
  handleSwipe(index: number, offsetX: number) {
    // 限制滑动范围(-200到0,200为删除按钮宽度)
    if (offsetX < -200) offsetX = -200;
    if (offsetX > 0) offsetX = 0;
    this.deleteOffsetX[index] = offsetX;
  }

  // 删除列表项(带动画)
  deleteItem(index: number) {
    animateTo({
      duration: 500,
      curve: Curve.EaseOut
    }, () => {
      this.deleteOffsetX[index] = -this.taskList.length * 200; // 快速滑出屏幕
    }, () => {
      this.taskList.splice(index, 1);
      this.deleteOffsetX.splice(index, 1); // 移除对应位移状态
    });
  }

  build() {
    Column({ space: 15 })
      .width('100%')
      .padding(30)
      .backgroundColor('#f5f5f5') {
      
      Text('滑动删除列表')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .marginBottom(20)

      List({ space: 10 }) {
        ForEach(this.taskList, (task, index) => {
          ListItem() {
            Stack() {
              // 删除按钮(默认隐藏在右侧)
              Button('删除')
                .width(200)
                .height('100%')
                .backgroundColor('#ff4d4f')
                .alignContent(FlexAlign.Center)
                .position({ x: '100%', left: -200 })

              // 列表项内容(可滑动)
              Text(task)
                .width('100%')
                .height(80)
                .lineHeight(80)
                .padding(20)
                .backgroundColor('#ffffff')
                .borderRadius(12)
                .translate({ x: this.deleteOffsetX[index] })
                .onTouch((e) => {
                  if (e.type === TouchType.MOVE) {
                    // 监听滑动事件,更新位移
                    this.handleSwipe(index, e.touches[0].x - e.touches[0].startX);
                  } else if (e.type === TouchType.END) {
                    // 滑动距离不足100,回弹
                    if (this.deleteOffsetX[index] > -100) {
                      animateTo({ duration: 300 }, () => {
                        this.deleteOffsetX[index] = 0;
                      });
                    }
                  }
                })
            }
          }
        })
      }

      Button('跳转到详情页(渐变效果)')
        .type(ButtonType.Capsule)
        .width(250)
        .height(50)
        .backgroundColor('#2f54eb')
        .marginTop(30)
        .onClick(() => {
          router.pushUrl({ url: 'pages/DetailPage' });
        })
    }
  }
}

// 详情页(复用页面渐变转场)
@Entry
@Component
struct DetailPage {
  build() {
    Column()
      .width('100%')
      .height('100%')
      .backgroundColor('#f5f5f5')
      .justifyContent(FlexAlign.Center) {
      
      Text('详情页')
        .fontSize(32)
        .fontWeight(FontWeight.Bold)

      Button('返回列表页')
        .type(ButtonType.Capsule)
        .width(200)
        .height(50)
        .backgroundColor('#ff4d4f')
        .marginTop(30)
        .onClick(() => {
          router.backUrl();
        })
    }
  }

  pageTransition() {
    PageTransition()
      .enter('fade', { duration: 800, curve: Curve.EaseInOut })
      .exit('fade', { duration: 800, curve: Curve.EaseInOut })
  }
}

2. 核心效果说明

  • 列表项滑动:通过onTouch监听滑动事件,animateTo控制translate位移,实现滑动露出删除按钮;
  • 删除动画:点击删除后,列表项快速滑出屏幕,动画结束后移除数据;
  • 页面渐变:通过pageTransition配置fade效果,跳转和返回时均有平滑渐变过渡。

五、实战踩坑指南

1. 动画不生效

  • 确保属性是「响应式状态」:必须用@State/@Link等装饰器,普通变量修改无法触发动画;
  • 动画函数包裹正确:animateTo的回调函数内必须直接修改属性,不可嵌套异步操作;
  • 版本适配:HarmonyOS 5.0 + 支持PageTransitionfade/slide简化配置,低版本需手动配置TransitionEffect

2. 滑动删除效果异常

  • 限制滑动范围:避免滑动过度导致 UI 错乱,建议限制在删除按钮宽度范围内;
  • 状态同步:deleteOffsetX数组需与列表数据一一对应,删除数据时同步移除对应位移状态。

3. 转场效果卡顿

  • 减少动画元素:避免同时对多个复杂组件添加动画;
  • 简化动画逻辑:优先使用系统提供的fade/slide等基础效果,自定义动画避免复杂计算。

加入班级,学习鸿蒙开发

相关推荐
Monkey_246 小时前
鸿蒙开发工具大全
华为·harmonyos
灰灰勇闯IT8 小时前
鸿蒙 5.0 开发入门第二篇:掌握 ArkTS 的 if 分支语句,实现条件逻辑判断
华为·harmonyos
2501_925317138 小时前
[鸿蒙2025领航者闯关] 把小智AI装进「第二大脑」:从开箱到MCP智能体的全链路实战
人工智能·microsoft·harmonyos·鸿蒙2025领航者闯关·小智ai智能音箱·mcp开发
柒儿吖8 小时前
让终端输出更美观:term_grid网格布局工具在OpenHarmony PC上的完整适配实战
harmonyos
柒儿吖9 小时前
深度实战:Rust交叉编译适配OpenHarmony PC——terminal_size完整适配案例
后端·rust·harmonyos
hh.h.9 小时前
Flutter应用嵌入鸿蒙智慧座舱数字孪生界面的实现
华为·harmonyos
白茶三许10 小时前
【江鸟中原】集光鸿蒙项目开发
pytorch·深度学习·harmonyos
zhujian8263710 小时前
二十一、【鸿蒙 NEXT】分词和汉字转拼音
华为·harmonyos·分词·汉字转拼音·分词ui卡顿
深海的鲸同学 luvi11 小时前
在鸿蒙设备上,如何启动一个真正可用的本地 Web 服务
华为·harmonyos