1.创建空白项目
2.Page文件夹下面新建Spin.ets文件,代码如下:
interface GridItemConfig {
translate:Translate
}
interface Translate {
x?: number;
y?: number;
}
/**
* TODO SpinKit动画组件(重构版)
* author: 鸿蒙布道师
* since: 2025/05/15
*/
@ComponentV2
export struct SpinNine {
@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() {
ForEach(this.getGridItems(), (item:GridItemConfig, index) => {
GridItem() {
Canvas()
.chunkStyle()
}
.translate(item.translate)
});
}
.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();
})
}
// 获取 GridItem 配置数据
private getGridItems():GridItemConfig[] {
return [
{ translate: { x: this.tran1 } },
{ translate: { x: this.tran1 } },
{ translate: { y: this.tran1 } },
{ translate: { y: -this.tran1 } },
{ translate: {} }, // 中心无位移
{ translate: { y: this.tran1 } },
{ translate: { y: -this.tran1 } },
{ translate: { x: -this.tran1 } },
{ translate: { x: -this.tran1 } },
];
}
// 启动动画
private startAnimation() {
this.getUIContext().keyframeAnimateTo({ iterations: -1, delay: 0 }, [
{
duration: 600,
curve: Curve.EaseInOut,
event: () => {
this.tran1 = 0;
this.scaleSize = this.oldSize * 1.1;
}
},
{
duration: 600,
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)
}
}
代码如下:
TypeScript
interface GridItemConfig {
translate:Translate
}
interface Translate {
x?: number;
y?: number;
}
/**
* TODO SpinKit动画组件(重构版)
* author: 鸿蒙布道师
* since: 2025/05/15
*/
@ComponentV2
export struct SpinNine {
@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() {
ForEach(this.getGridItems(), (item:GridItemConfig, index) => {
GridItem() {
Canvas()
.chunkStyle()
}
.translate(item.translate)
});
}
.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();
})
}
// 获取 GridItem 配置数据
private getGridItems():GridItemConfig[] {
return [
{ translate: { x: this.tran1 } },
{ translate: { x: this.tran1 } },
{ translate: { y: this.tran1 } },
{ translate: { y: -this.tran1 } },
{ translate: {} }, // 中心无位移
{ translate: { y: this.tran1 } },
{ translate: { y: -this.tran1 } },
{ translate: { x: -this.tran1 } },
{ translate: { x: -this.tran1 } },
];
}
// 启动动画
private startAnimation() {
this.getUIContext().keyframeAnimateTo({ iterations: -1, delay: 0 }, [
{
duration: 600,
curve: Curve.EaseInOut,
event: () => {
this.tran1 = 0;
this.scaleSize = this.oldSize * 1.1;
}
},
{
duration: 600,
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 { SpinEight } from './Spin';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
SpinNine({
spinSize: 60,
spinColor: '#FF0000'
})
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
}
}
代码如下:
TypeScript
import { SpinEight } from './Spin';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
SpinNine({
spinSize: 60,
spinColor: '#FF0000'
})
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
}
}
4.运行项目,登录华为账号,需进行签名
5.动画效果如下:
