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) } }
// ===== 接口定义(必须放在使用前)=====
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%') } }
代码如下:
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.动画效果如下: