一、粒子动画实现动态标题
二、效果:
三、实现思路:
1、使用Column 和 stack布局
2、粒子效果覆盖在文本上方
3、粒子效果实现
Particle({
particles: [
// 第一种粒子
{
emitter: { ... }, // 发射器配置
color: { ... }, // 颜色配置
opacity: { ... }, // 透明度配置
scale: { ... }, // 缩放配置
acceleration: { ... } // 加速度配置
},
// 第二种粒子
{ ... }
]
}).width(150).height(100)
4、粒子发射器配置
emitter: {
particle: {
type: ParticleType.IMAGE, // 使用图片作为粒子
config: {
src: $r("app.media.animation_xin"), // 粒子图片资源
size: [10, 10] // 粒子大小
},
count: this.myCount, // 粒子数量
lifetime: 7000, // 粒子生命周期(毫秒)
lifetimeRange: 100 // 生命周期随机范围
},
emitRate: 3, // 发射速率(粒子/秒)
position: [0.5, 1.0], // 发射位置(相对坐标)
shape: ParticleEmitterShape.CIRCLE // 发射形状(圆形)
}
5、动画效果实现:使用了两种粒子,第一种粒子生命周期 7 秒,从底部中心向上发射,有完整的透明度和缩放变化;第二个粒子生命周期 8 秒,默认从左上角发射,与第一种粒子类似的动画效果,但持续时间不同。
opacity: {
range: [1.0, 1.0],
updater: {
type: ParticleUpdater.CURVE,
config: [
{
from: 0, to: 1.0, // 从不透明到完全透明
startMillis: 0, endMillis: 2000 // 时间范围
},
{
from: 1.0, to: .0, // 从完全透明到消失
startMillis: 2000, endMillis: 4000
}
]
}
}
四、代码实现: myCount
变量来控制粒子的密集程度
@Entry
@Component
struct ParticleExample {
@State
myCount: number = 100
flag: boolean = false;
build() {
Column() {
Stack() {
Text('云音乐').fontSize(25).fontWeight('bold')
Particle({
particles: [
{
emitter: {
particle: {
type: ParticleType.IMAGE,
config: {
src: $r("app.media.animation_xin"),
size: [10, 10]
},
count: this.myCount,
lifetime: 7000,
lifetimeRange: 100
},
emitRate: 3,
position: [0.5, 1.0],
shape: ParticleEmitterShape.CIRCLE
},
color: {
range: [Color.White, Color.White]
},
opacity: {
range: [1.0, 1.0],
updater: {
type: ParticleUpdater.CURVE,
config: [
{
from: 0,
to: 1.0,
startMillis: 0,
endMillis: 2000
},
{
from: 1.0,
to: .0,
startMillis: 2000,
endMillis: 4000
}
]
}
},
scale: {
range: [0.8, 2.0],
updater: {
type: ParticleUpdater.CURVE,
config: [
{
from: 0.8,
to: 1.5,
startMillis: 0,
endMillis: 3000,
curve: Curve.EaseIn
},
{
from: 1.5,
to: 2.0,
startMillis: 3000,
endMillis: 4000,
curve: Curve.EaseIn
}
]
}
},
acceleration: {
speed: {
range: [3, 9],
updater: {
type: ParticleUpdater.CURVE,
config: [
{
from: 10,
to: 50,
startMillis: 0,
endMillis: 5000,
curve: Curve.EaseIn
},
]
}
},
angle: {
range: [270,270],
updater: {
type: ParticleUpdater.CURVE,
config: [{
from: 270,
to: 270,
startMillis: 0,
endMillis: 5000,
curve: Curve.EaseIn
},
]
}
}
},
}
, {
emitter: {
particle: {
type: ParticleType.IMAGE,
config: {
src: $r('app.media.search_x1'),
size: [10, 10]
},
count: this.myCount,
lifetime: 8000,
lifetimeRange: 100
},
emitRate: 3,
shape: ParticleEmitterShape.CIRCLE
},
color: {
range: [Color.White, Color.White]
},
opacity: {
range: [1.0, 1.0],
updater: {
type: ParticleUpdater.CURVE,
config: [
{
from: 0,
to: 1.0,
startMillis: 0,
endMillis: 2000
},
{
from: 1.0,
to: .0,
startMillis: 2000,
endMillis: 3000
}
]
}
},
scale: {
range: [0.8, 2.0],
updater: {
type: ParticleUpdater.CURVE,
config: [
{
from: 0.8,
to: 1.5,
startMillis: 0,
endMillis: 3000,
curve: Curve.EaseIn
},
{
from: 1.5,
to: 2.0,
startMillis: 3000,
endMillis: 4000,
curve: Curve.EaseIn
}
]
}
},
acceleration: {
speed: {
range: [3, 9],
updater: {
type: ParticleUpdater.CURVE,
config: [
{
from: 10,
to: 50,
startMillis: 0,
endMillis: 5000,
curve: Curve.EaseIn
},
]
}
},
angle: {
range: [270, 270],
updater: {
type: ParticleUpdater.CURVE,
config: [{
from: 270,
to: 270,
startMillis: 0,
endMillis: 5000,
curve: Curve.EaseIn
},
]
}
}
},
}
]
}).width(150).height(100)
}.width(500).align(Alignment.Center).height(100).margin({top:200})
// .backgroundColor(Color.Pink)
}.width("100%").height(100)
}
}