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