鸿蒙NEXT开发动画案例7

 1.创建空白项目


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

/**
 * TODO SpinKit动画组件 - DotPulse 三点脉冲动画
 * author: CSDN-鸿蒙布道师
 * since: 2025/05/13
 */
@ComponentV2
export struct SpinSeven {
  // 参数定义
  @Require @Param spinSize: number = 48;
  @Require @Param spinColor: ResourceColor = '#209ED8';

  // 局部状态
  @Local scale1: number = 1;
  @Local scale2: number = 0.5;
  @Local scale3: number = 0;

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

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

      Canvas()
        .chunkStyle()
        .scale({ x: this.scale3, y: this.scale3 })
    }
    .width(this.spinSize)
    .height(this.spinSize / 3)
    .onAppear(() => {
      this.startAnimation();
    });
  }

  /**
   * 启动无限循环的关键帧动画
   */
  private startAnimation(): void {
    const uiContext = this.getUIContext();
    if (!uiContext) return;

    const keyframes1 = this.createKeyframes(
      (value: number) => { this.scale1 = value; },
      [0, 1, 1]
    );
    const keyframes2 = this.createKeyframes(
      (value: number) => { this.scale2 = value; },
      [1, 0, 0.5]
    );
    const keyframes3 = this.createKeyframes(
      (value: number) => { this.scale3 = value; },
      [1, 0, 0]
    );

    uiContext.keyframeAnimateTo(
      { iterations: -1, delay: 280 },
      keyframes1
    );
    uiContext.keyframeAnimateTo(
      { iterations: -1, delay: 120 },
      keyframes2
    );
    uiContext.keyframeAnimateTo(
      { iterations: -1, delay: 0 },
      keyframes3
    );
  }

  /**
   * 创建通用的缩放动画关键帧序列
   * @param updateFn 更新状态的方法
   * @param values 要依次应用的 scale 值数组
   */
  private createKeyframes(
    updateFn: (value: number) => void,
    values: number[]
  ): Array<KeyframeState> {
    const keyframes: Array<KeyframeState> = [];

    values.forEach((value, index) => {
      keyframes.push({
        duration: index === 0 || index === 2 ? 280 : 560,
        curve: Curve.Linear,
        event: (): void => {
          updateFn(value);
        }
      });
    });

    // 补充空帧用于节奏同步
    keyframes.push({
      duration: 280,
      event: (): void => {}
    });

    return keyframes;
  }

  @Styles
  chunkStyle() {
    .height(this.spinSize / 3)
    .width(this.spinSize / 3)
    .borderRadius(this.spinSize / 3)
    .backgroundColor(this.spinColor)
    .shadow(ShadowStyle.OUTER_DEFAULT_XS)
  }
}
代码如下:
/**
 * TODO SpinKit动画组件 - DotPulse 三点脉冲动画
 * author: CSDN-鸿蒙布道师
 * since: 2025/05/13
 */
@ComponentV2
export struct SpinSeven {
  // 参数定义
  @Require @Param spinSize: number = 48;
  @Require @Param spinColor: ResourceColor = '#209ED8';

  // 局部状态
  @Local scale1: number = 1;
  @Local scale2: number = 0.5;
  @Local scale3: number = 0;

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

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

      Canvas()
        .chunkStyle()
        .scale({ x: this.scale3, y: this.scale3 })
    }
    .width(this.spinSize)
    .height(this.spinSize / 3)
    .onAppear(() => {
      this.startAnimation();
    });
  }

  /**
   * 启动无限循环的关键帧动画
   */
  private startAnimation(): void {
    const uiContext = this.getUIContext();
    if (!uiContext) return;

    const keyframes1 = this.createKeyframes(
      (value: number) => { this.scale1 = value; },
      [0, 1, 1]
    );
    const keyframes2 = this.createKeyframes(
      (value: number) => { this.scale2 = value; },
      [1, 0, 0.5]
    );
    const keyframes3 = this.createKeyframes(
      (value: number) => { this.scale3 = value; },
      [1, 0, 0]
    );

    uiContext.keyframeAnimateTo(
      { iterations: -1, delay: 280 },
      keyframes1
    );
    uiContext.keyframeAnimateTo(
      { iterations: -1, delay: 120 },
      keyframes2
    );
    uiContext.keyframeAnimateTo(
      { iterations: -1, delay: 0 },
      keyframes3
    );
  }

  /**
   * 创建通用的缩放动画关键帧序列
   * @param updateFn 更新状态的方法
   * @param values 要依次应用的 scale 值数组
   */
  private createKeyframes(
    updateFn: (value: number) => void,
    values: number[]
  ): Array<KeyframeState> {
    const keyframes: Array<KeyframeState> = [];

    values.forEach((value, index) => {
      keyframes.push({
        duration: index === 0 || index === 2 ? 280 : 560,
        curve: Curve.Linear,
        event: (): void => {
          updateFn(value);
        }
      });
    });

    // 补充空帧用于节奏同步
    keyframes.push({
      duration: 280,
      event: (): void => {}
    });

    return keyframes;
  }

  @Styles
  chunkStyle() {
    .height(this.spinSize / 3)
    .width(this.spinSize / 3)
    .borderRadius(this.spinSize / 3)
    .backgroundColor(this.spinColor)
    .shadow(ShadowStyle.OUTER_DEFAULT_XS)
  }
}

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

import { SpinSeven } from './Spin';

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

  build() {
    Column() {
      SpinSeven({
        spinSize: 60,
        spinColor: '#FF0000'
      })
    }
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }
}
代码如下:
import { SpinSeven } from './Spin';

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

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

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

5.动画效果如下:
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值