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

相关推荐
鸿蒙布道师3 小时前
AI原生手机:三大技术阵营的终极对决与未来展望
android·人工智能·ios·华为·智能手机·ai-native·hauwei
每次的天空3 小时前
移动应用开发:自定义 View 处理大量数据的性能与交互优化方案
android·java·学习·交互
雪芽蓝域zzs4 小时前
HarmonyOS开发-组件市场
华为·harmonyos
Huang兄4 小时前
Android 项目中配置了多个 maven 仓库,但依赖还是下载失败,除了使用代理,还有其他方法吗?
android·gradle·maven
Johny_Zhao5 小时前
堆叠、MLAG、VPC、VSS 技术对比及架构建议
linux·网络·人工智能·python·网络安全·ai·信息安全·云计算·cisco·等保测评·huawei·系统运维
Echo-潔5 小时前
iOS创建Certificate证书、制作p12证书流程
ios·ios 生成app打包证书
snail2012115 小时前
Flutter接入ProtoBuff和原生Android通信【性能最优】
android·flutter
難釋懷6 小时前
Android开发-常用布局
android·gitee
__Benco6 小时前
OpenHarmony平台驱动开发(十),MMC
人工智能·驱动开发·harmonyos