鸿蒙NEXT开发动画案例10

 1.创建空白项目


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

interface TranslateOffset {
  x?:number
  y?:number
}
/**
 * SpinKit动画组件 - SpinTen
 * author: CSDN-鸿蒙布道师
 * since: 2025/05/16
 */
@ComponentV2
export struct SpinTen {
  @Require @Param spinSize: number = 36;
  @Require @Param spinColor: ResourceColor;

  @Local scaleSize: number = this.spinSize * 0.75;
  @Local tran1: number = 0;
  private oldSize: number = this.spinSize;

  aboutToAppear(): void {
    this.oldSize = this.spinSize;
    this.scaleSize = this.spinSize * 0.75;
  }

  build() {
    Stack() {
      Grid() {
        // 使用循环构建9个 GridItem
        ForEach([0, 1, 2, 3, 4, 5, 6, 7, 8], (index: number) => {
          GridItem() {
            Canvas()
              .chunkStyle()
          }
          .translate(this.getTranslateOffset(index))
        })
      }
      .rowsTemplate('1fr 1fr 1fr')
      .columnsTemplate('1fr 1fr 1fr')
      .width(this.scaleSize)
      .height(this.scaleSize)
    }
    .width(this.oldSize)
    .height(this.oldSize)
    .alignContent(Alignment.Center)
    .onAppear(() => {
      this.startAnimation();
    })
  }

  // 抽取 translate 偏移量计算逻辑
  getTranslateOffset(index: number): TranslateOffset {
    switch (index) {
      case 0: return { x: this.tran1 };
      case 1: return { x: this.tran1 };
      case 2: return { y: this.tran1 };
      case 3: return { y: -this.tran1 };
      case 4: return {}; // 中间项无偏移
      case 5: return { y: this.tran1 };
      case 6: return { y: -this.tran1 };
      case 7: return { x: -this.tran1 };
      case 8: return { x: -this.tran1 };
      default: return {};
    }
  }

  // 启动 Keyframe 动画
  startAnimation(): void {
    this.getUIContext().keyframeAnimateTo({ iterations: -1, delay: 0 }, [
      {
        duration: 500,
        curve: Curve.EaseInOut,
        event: () => {
          this.tran1 = 0;
          this.scaleSize = this.oldSize * 1.1;
        }
      },
      {
        duration: 190,
        curve: Curve.Linear,
        event: () => {
          this.tran1 = this.oldSize / 3;
        }
      },
      {
        duration: 0,
        curve: Curve.Linear,
        event: () => {
          this.tran1 = 0;
        }
      },
      {
        duration: 10,
        curve: Curve.Linear,
        event: () => {}
      },
      {
        duration: 500,
        curve: Curve.EaseIn,
        event: () => {
          this.scaleSize = this.oldSize * 0.75;
          this.tran1 = 0;
        }
      }
    ]);
  }

  @Styles
  chunkStyle() {
    .width(this.oldSize * 0.25)
    .height(this.oldSize * 0.25)
    .backgroundColor(this.spinColor)
    .shadow(ShadowStyle.OUTER_DEFAULT_XS)
  }
}
代码如下:
interface TranslateOffset {
  x?:number
  y?:number
}
/**
 * SpinKit动画组件 - SpinTen
 * author: CSDN-鸿蒙布道师
 * since: 2025/05/16
 */
@ComponentV2
export struct SpinTen {
  @Require @Param spinSize: number = 36;
  @Require @Param spinColor: ResourceColor;

  @Local scaleSize: number = this.spinSize * 0.75;
  @Local tran1: number = 0;
  private oldSize: number = this.spinSize;

  aboutToAppear(): void {
    this.oldSize = this.spinSize;
    this.scaleSize = this.spinSize * 0.75;
  }

  build() {
    Stack() {
      Grid() {
        // 使用循环构建9个 GridItem
        ForEach([0, 1, 2, 3, 4, 5, 6, 7, 8], (index: number) => {
          GridItem() {
            Canvas()
              .chunkStyle()
          }
          .translate(this.getTranslateOffset(index))
        })
      }
      .rowsTemplate('1fr 1fr 1fr')
      .columnsTemplate('1fr 1fr 1fr')
      .width(this.scaleSize)
      .height(this.scaleSize)
    }
    .width(this.oldSize)
    .height(this.oldSize)
    .alignContent(Alignment.Center)
    .onAppear(() => {
      this.startAnimation();
    })
  }

  // 抽取 translate 偏移量计算逻辑
  getTranslateOffset(index: number): TranslateOffset {
    switch (index) {
      case 0: return { x: this.tran1 };
      case 1: return { x: this.tran1 };
      case 2: return { y: this.tran1 };
      case 3: return { y: -this.tran1 };
      case 4: return {}; // 中间项无偏移
      case 5: return { y: this.tran1 };
      case 6: return { y: -this.tran1 };
      case 7: return { x: -this.tran1 };
      case 8: return { x: -this.tran1 };
      default: return {};
    }
  }

  // 启动 Keyframe 动画
  startAnimation(): void {
    this.getUIContext().keyframeAnimateTo({ iterations: -1, delay: 0 }, [
      {
        duration: 500,
        curve: Curve.EaseInOut,
        event: () => {
          this.tran1 = 0;
          this.scaleSize = this.oldSize * 1.1;
        }
      },
      {
        duration: 190,
        curve: Curve.Linear,
        event: () => {
          this.tran1 = this.oldSize / 3;
        }
      },
      {
        duration: 0,
        curve: Curve.Linear,
        event: () => {
          this.tran1 = 0;
        }
      },
      {
        duration: 10,
        curve: Curve.Linear,
        event: () => {}
      },
      {
        duration: 500,
        curve: Curve.EaseIn,
        event: () => {
          this.scaleSize = this.oldSize * 0.75;
          this.tran1 = 0;
        }
      }
    ]);
  }

  @Styles
  chunkStyle() {
    .width(this.oldSize * 0.25)
    .height(this.oldSize * 0.25)
    .backgroundColor(this.spinColor)
    .shadow(ShadowStyle.OUTER_DEFAULT_XS)
  }
}

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

import { SpinTen } from './Spin';

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

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

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

  build() {
    Column() {
      SpinTen({
        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、付费专栏及课程。

余额充值