鸿蒙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.动画效果如下:

相关推荐
mmsx14 小时前
Android 插件化架构:40 个 Gradle 模块的拆分、通信与共存
android·kotlin
mmsx14 小时前
Android 不改一行源码:用 AspectJ 做三类拦截
android·kotlin
TST-魚爷14 小时前
易视讯会议摄像头 + 全向麦克风实操讲解稿
android·电脑·钉钉·腾讯会议·zoom会议
嘟哩DuliDuli14 小时前
AI创作工作区的项目上下文与多模态任务边界
android·人工智能·安全·ai·软件工程
OH_TPC15 小时前
HarmonyOS APP开发---“习惯猫“习惯打卡App,需要用到这个库
华为·harmonyos·鸿蒙
Yannik16 小时前
iOS CocoaPods私有库完整搭建+踩坑实战总结
ios·cocoapods
imDwAaY16 小时前
MySQL 存储引擎是什么?
android·数据库·mysql
熊猫钓鱼>_>17 小时前
开源鸿蒙平台 KMP 三方库 kotlin-csv 适配全流程:从编码假设到沙箱真机互通验证
开发语言·人工智能·华为·kotlin·harmonyos·鸿蒙
Meteors.17 小时前
Android Compose学习02:基础组件与 Modifier
android·学习
其实防守也摸鱼18 小时前
存储管理:页面置换算法学习任务(测验题要求给出置换页面顺序,缺页次数,缺页率)
android·前端·数据库·学习·oracle·自动化