1.创建空白项目
2.Page文件夹下面新建Spin.ets文件,代码如下:
/** * SpinKit 风格的旋转加载动画组件。 * * @component * @param spinSize - 动画容器大小(必须为正数) * @param spinColor - 动画颜色(支持资源引用) * * 示例: * ```ets * SpinOne({ * spinSize: 60, * spinColor: '#FF0000' * }) * ``` */ // 定义关键帧动画配置接口 interface KeyframeItem { duration: number; curve: Curve; event: () => void; } // 动画整体配置接口(已存在) interface KeyframeAnimationConfig { iterations: number; delay: number; } // 更新动画状态的参数接口 interface AnimationUpdateParams { angle?: number; x?: number; y?: number; } @ComponentV2 export struct SpinOne { @Require @Param spinSize: number = 48; // 父组件必须传值,这里默认值不会实际生效 @Require @Param spinColor: ResourceColor = '#209ED8'; @Local angle: number = 0; @Local x: number = 0; @Local y: number = 0; private readonly ANIMATION_DURATION: number = 600; build() { Canvas() .width(this.spinSize) .height(this.spinSize) .backgroundColor(this.spinColor) .renderFit(RenderFit.CENTER) .shadow(ShadowStyle.OUTER_DEFAULT_XS) .rotate({ perspective: this.spinSize, x: this.x, y: this.y, angle: this.angle }) .onAppear(() => { this.startAnimation(); }); } private startAnimation(): void { const uiContext = this.getUIContext(); if (!uiContext) return; const animationConfig: KeyframeAnimationConfig = { iterations: -1, // 无限循环 delay: 0, }; uiContext.keyframeAnimateTo(animationConfig, [ this.createKeyframe(this.ANIMATION_DURATION, { angle: 180, x: this.spinSize / 2, y: 0 }), this.createKeyframe(0, { angle: 0 }), this.createKeyframe(this.ANIMATION_DURATION, { angle: 180, x: 0, y: this.spinSize / 2 }) ]); } /** * 创建关键帧动画配置项 * @param duration 动画持续时间 * @param update 动画更新参数 */ private createKeyframe( duration: number, update: AnimationUpdateParams ): KeyframeItem { return { duration, curve: Curve.EaseInOut, event: () => { if (update.angle !== undefined) this.angle = update.angle; if (update.x !== undefined) this.x = update.x; if (update.y !== undefined) this.y = update.y; } }; } } 代码如下:
/**
* SpinKit 风格的旋转加载动画组件。
*
* @component
* @param spinSize - 动画容器大小(必须为正数)
* @param spinColor - 动画颜色(支持资源引用)
*
* 示例:
* ```ets
* SpinOne({
* spinSize: 60,
* spinColor: '#FF0000'
* })
* ```
*/
// 定义关键帧动画配置接口
interface KeyframeItem {
duration: number;
curve: Curve;
event: () => void;
}
// 动画整体配置接口(已存在)
interface KeyframeAnimationConfig {
iterations: number;
delay: number;
}
// 更新动画状态的参数接口
interface AnimationUpdateParams {
angle?: number;
x?: number;
y?: number;
}
@ComponentV2
export struct SpinOne {
@Require @Param spinSize: number = 48; // 父组件必须传值,这里默认值不会实际生效
@Require @Param spinColor: ResourceColor = '#209ED8';
@Local angle: number = 0;
@Local x: number = 0;
@Local y: number = 0;
private readonly ANIMATION_DURATION: number = 600;
build() {
Canvas()
.width(this.spinSize)
.height(this.spinSize)
.backgroundColor(this.spinColor)
.renderFit(RenderFit.CENTER)
.shadow(ShadowStyle.OUTER_DEFAULT_XS)
.rotate({
perspective: this.spinSize,
x: this.x,
y: this.y,
angle: this.angle
})
.onAppear(() => {
this.startAnimation();
});
}
private startAnimation(): void {
const uiContext = this.getUIContext();
if (!uiContext) return;
const animationConfig: KeyframeAnimationConfig = {
iterations: -1, // 无限循环
delay: 0,
};
uiContext.keyframeAnimateTo(animationConfig, [
this.createKeyframe(this.ANIMATION_DURATION, { angle: 180, x: this.spinSize / 2, y: 0 }),
this.createKeyframe(0, { angle: 0 }),
this.createKeyframe(this.ANIMATION_DURATION, { angle: 180, x: 0, y: this.spinSize / 2 })
]);
}
/**
* 创建关键帧动画配置项
* @param duration 动画持续时间
* @param update 动画更新参数
*/
private createKeyframe(
duration: number,
update: AnimationUpdateParams
): KeyframeItem {
return {
duration,
curve: Curve.EaseInOut,
event: () => {
if (update.angle !== undefined) this.angle = update.angle;
if (update.x !== undefined) this.x = update.x;
if (update.y !== undefined) this.y = update.y;
}
};
}
}
3.修改Index.ets文件,代码如下:
import { SpinOne } from './Spin';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
SpinOne({
spinSize: 60,
spinColor: '#FF0000'
})
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
}
}
代码如下:
import { SpinOne } from './Spin';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
SpinOne({
spinSize: 60,
spinColor: '#FF0000'
})
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
}
}
4.运行项目,登录华为账号,需进行签名
5.动画效果如下: