鸿蒙NEXT开发动画案例3

1.创建空白项目

2.Page文件夹下面新建Spin.ets文件,代码如下:

复制代码
// ===== 接口定义(必须放在使用前)=====
interface KeyframeAnimationConfig {
  iterations: number;
  delay: number;
}

interface KeyframeState {
  duration: number;
  curve?: Curve;
  event: () => void;
}
// ===== 接口定义结束 =====


/**
 * TODO SpinKit动画组件
 * author: 鸿蒙布道师
 * since: 2025/05/07
 */
@ComponentV2
export struct SpinThree {
  // 参数定义
  @Require @Param spinSize: number = 48;
  @Require @Param spinColor: ResourceColor = '#209ED8';

  // 动画状态
  @Local scale1: number = 0.4;
  @Local scale2: number = 0.4;
  @Local scale3: number = 0.4;
  @Local scale4: number = 0.4;
  @Local scale5: number = 0.4;

  build() {
    Row() {
      Canvas()
        .chunkStyle()
        .scale({ y: this.scale1 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale2 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale3 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale4 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale5 })
    }
    .width(this.spinSize)
    .height(this.spinSize * 0.8)
    .onAppear(() => {
      this.startAnimations();
    });
  }

  /**
   * 启动所有子动画
   */
  private startAnimations(): void {
    const uiContext = this.getUIContext();
    if (!uiContext) return;

    const ANIMATION_DELAY_INTERVAL = 100; // 每个动画延迟间隔

    for (let i = 1; i <= 5; i++) {
      const keyframes = this.createKeyframes(i);
      const delay = -1100 + (i - 1) * ANIMATION_DELAY_INTERVAL;

      uiContext.keyframeAnimateTo(
        { iterations: -1, delay },
        keyframes
      );
    }
  }

  /**
   * 根据索引创建对应的关键帧动画
   * @param index - 第几个动画(1~5)
   */
  private createKeyframes(index: number): Array<KeyframeState> {
    const updateScale = (value: number) => {
      switch (index) {
        case 1: this.scale1 = value; break;
        case 2: this.scale2 = value; break;
        case 3: this.scale3 = value; break;
        case 4: this.scale4 = value; break;
        case 5: this.scale5 = value; break;
      }
    };

    return [
      {
        duration: 240,
        curve: Curve.EaseInOut,
        event: ():void => updateScale(1),
      },
      {
        duration: 240,
        curve: Curve.EaseInOut,
        event: ():void => updateScale(0.4),
      },
      {
        duration: 720,
        event: () => {},
      }
    ];
  }

  /**
   * 公共样式封装
   */
  @Styles
  chunkStyle() {
    .height('100%')
    .width('14%')
    .margin({ left: '3%', right: '3%' })
    .backgroundColor(this.spinColor)
    .shadow(ShadowStyle.OUTER_DEFAULT_XS)
  }
}
TypeScript 复制代码
// ===== 接口定义(必须放在使用前)=====
interface KeyframeAnimationConfig {
  iterations: number;
  delay: number;
}

interface KeyframeState {
  duration: number;
  curve?: Curve;
  event: () => void;
}
// ===== 接口定义结束 =====


/**
 * TODO SpinKit动画组件
 * author: 鸿蒙布道师
 * since: 2025/05/07
 */
@ComponentV2
export struct SpinThree {
  // 参数定义
  @Require @Param spinSize: number = 48;
  @Require @Param spinColor: ResourceColor = '#209ED8';

  // 动画状态
  @Local scale1: number = 0.4;
  @Local scale2: number = 0.4;
  @Local scale3: number = 0.4;
  @Local scale4: number = 0.4;
  @Local scale5: number = 0.4;

  build() {
    Row() {
      Canvas()
        .chunkStyle()
        .scale({ y: this.scale1 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale2 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale3 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale4 })

      Canvas()
        .chunkStyle()
        .scale({ y: this.scale5 })
    }
    .width(this.spinSize)
    .height(this.spinSize * 0.8)
    .onAppear(() => {
      this.startAnimations();
    });
  }

  /**
   * 启动所有子动画
   */
  private startAnimations(): void {
    const uiContext = this.getUIContext();
    if (!uiContext) return;

    const ANIMATION_DELAY_INTERVAL = 100; // 每个动画延迟间隔

    for (let i = 1; i <= 5; i++) {
      const keyframes = this.createKeyframes(i);
      const delay = -1100 + (i - 1) * ANIMATION_DELAY_INTERVAL;

      uiContext.keyframeAnimateTo(
        { iterations: -1, delay },
        keyframes
      );
    }
  }

  /**
   * 根据索引创建对应的关键帧动画
   * @param index - 第几个动画(1~5)
   */
  private createKeyframes(index: number): Array<KeyframeState> {
    const updateScale = (value: number) => {
      switch (index) {
        case 1: this.scale1 = value; break;
        case 2: this.scale2 = value; break;
        case 3: this.scale3 = value; break;
        case 4: this.scale4 = value; break;
        case 5: this.scale5 = value; break;
      }
    };

    return [
      {
        duration: 240,
        curve: Curve.EaseInOut,
        event: ():void => updateScale(1),
      },
      {
        duration: 240,
        curve: Curve.EaseInOut,
        event: ():void => updateScale(0.4),
      },
      {
        duration: 720,
        event: () => {},
      }
    ];
  }

  /**
   * 公共样式封装
   */
  @Styles
  chunkStyle() {
    .height('100%')
    .width('14%')
    .margin({ left: '3%', right: '3%' })
    .backgroundColor(this.spinColor)
    .shadow(ShadowStyle.OUTER_DEFAULT_XS)
  }
}

3.修改Index.ets文件,代码如下:

复制代码
import { SpinThree } from './Spin';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    Column() {
      SpinThree({
        spinSize: 60,
        spinColor: '#FF0000'
      })
    }
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }
}

代码如下:

TypeScript 复制代码
import { SpinThree } from './Spin';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    Column() {
      SpinThree({
        spinSize: 60,
        spinColor: '#FF0000'
      })
    }
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }
}

4.运行项目,登录华为账号,需进行签名

5.动画效果如下:

相关推荐
上海张律师27 分钟前
组件截图sdk -- screenshot_hm介绍 ##三方SDK##
前端·harmonyos
墨狂之逸才28 分钟前
kotlin泛型实化
android·kotlin
_一条咸鱼_28 分钟前
Android Runtime虚拟机实例创建与全局状态初始化(11)
android·面试·android jetpack
墨狂之逸才30 分钟前
kotlin中:: 是一个非常重要的操作符,称为引用操作符
android·kotlin
lqj_本人31 分钟前
鸿蒙OS&UniApp 移动端直播流播放实战:打造符合鸿蒙设计风格的播放器#三方框架 #Uniapp
华为·uni-app·harmonyos
lqj_本人35 分钟前
鸿蒙OS&UniApp复杂表单与动态验证实践:打造高效的移动端表单解决方案#三方框架 #Uniapp
华为·uni-app·harmonyos
工业互联网专业1 小时前
基于Android的记录生活APP_springboot+vue
android·vue.js·spring boot·毕业设计·源码·课程设计·记录生活app
小陶来咯1 小时前
【仿muduo库实现并发服务器】实现时间轮定时器
android·运维·服务器
移动端开发者1 小时前
鸿蒙Next Tabs实现底部导航进阶
harmonyos
simple丶1 小时前
【HarmonyOS 】工具函数封装 持续更迭...
harmonyos·arkts·arkui