鸿蒙跨端点赞按钮动画设计与实现
基于HarmonyOS的动画能力,我们设计了一个跨设备同步的点赞按钮动画,确保在多设备游戏场景中点赞状态和动画效果能够实时同步。https://example.com/like-animation-preview.gif动画包含三个核心效果:2. 增强版点赞动画(带粒子效果)3. 跨设备同步实现(Java)三、动画参数详解1. 动画曲线对比曲线类型描述适用场景动画开始时慢,然后加速元素离开屏幕
·
鸿蒙跨端点赞按钮动画设计与实现
一、动画效果设计
基于HarmonyOS的动画能力,我们设计了一个跨设备同步的点赞按钮动画,确保在多设备游戏场景中点赞状态和动画效果能够实时同步。
https://example.com/like-animation-preview.gif
动画包含三个核心效果:
- 缩放效果 - 点击时按钮先缩小后恢复
- 颜色渐变 - 点赞状态切换时的颜色过渡
- 粒子效果 - 点赞成功时的粒子飞散效果
二、核心代码实现
1. 基础点赞按钮组件(ArkTS)
// LikeButton.ets
@Component
export struct LikeButton {
@State isLiked: boolean = false
@State scaleValue: number = 1
@State bgColor: Color = Color.White
build() {
Button() {
Image(this.isLiked ? $r('app.media.liked') : $r('app.media.unliked'))
.width(24)
.height(24)
}
.width(48)
.height(48)
.borderRadius(24)
.backgroundColor(this.bgColor)
.scale({ x: this.scaleValue, y: this.scaleValue })
.onClick(() => this.handleLike())
}
private handleLike() {
// 触发动画
this.startAnimation()
// 切换点赞状态
this.isLiked = !this.isLiked
// 跨设备同步状态
this.syncLikeState()
}
private startAnimation() {
// 缩放动画
animateTo({
duration: 200,
curve: Curve.EaseOut
}, () => {
this.scaleValue = 0.8
})
// 颜色变化动画
animateTo({
duration: 300,
curve: Curve.EaseInOut,
delay: 100
}, () => {
this.bgColor = this.isLiked ?
Color.White :
Color.fromRGB(255, 228, 225)
})
// 恢复动画
animateTo({
duration: 200,
curve: Curve.EaseIn,
delay: 200
}, () => {
this.scaleValue = 1
})
}
private syncLikeState() {
// 通过分布式数据管理同步状态
distributedData.sync('like_state', {
isLiked: this.isLiked,
timestamp: new Date().getTime()
})
}
}
2. 增强版点赞动画(带粒子效果)
// AdvancedLikeButton.ets
@Component
export struct AdvancedLikeButton {
@State isLiked: boolean = false
@State scaleValue: number = 1
@State bgColor: Color = Color.White
@State particles: Particle[] = []
@Builder
ParticleEffect() {
ForEach(this.particles, (particle) => {
Circle()
.width(particle.size)
.height(particle.size)
.position(particle.position)
.backgroundColor(particle.color)
.opacity(particle.opacity)
})
}
build() {
Stack() {
// 粒子效果层
this.ParticleEffect()
// 按钮层
Button() {
Image(this.isLiked ? $r('app.media.liked_filled') : $r('app.media.unliked'))
.width(28)
.height(28)
}
.width(56)
.height(56)
.borderRadius(28)
.backgroundColor(this.bgColor)
.scale({ x: this.scaleValue, y: this.scaleValue })
.onClick(() => this.handleLike())
}
.width(100)
.height(100)
}
private handleLike() {
// 触发动画
this.startAnimation()
// 切换点赞状态
this.isLiked = !this.isLiked
// 如果是点赞状态,生成粒子效果
if (this.isLiked) {
this.generateParticles()
}
// 跨设备同步状态
this.syncLikeState()
}
private startAnimation() {
// 第一阶段:缩小和颜色变化
animateTo({
duration: 150,
curve: Curve.EaseOut
}, () => {
this.scaleValue = 0.85
this.bgColor = this.isLiked ?
Color.fromRGB(255, 228, 225) :
Color.fromRGB(240, 240, 240)
})
// 第二阶段:恢复和最终颜色
animateTo({
duration: 250,
curve: Curve.Spring,
delay: 150
}, () => {
this.scaleValue = 1
this.bgColor = this.isLiked ?
Color.fromRGB(255, 192, 203) :
Color.White
})
}
private generateParticles() {
// 清空现有粒子
this.particles = []
// 生成20个粒子
const newParticles: Particle[] = []
for (let i = 0; i < 20; i++) {
newParticles.push(this.createParticle(i))
}
this.particles = newParticles
// 粒子动画
animateTo({
duration: 800,
curve: Curve.Friction
}, () => {
this.particles = this.particles.map(p => ({
...p,
position: {
x: p.position.x + p.velocity.x * 2,
y: p.position.y + p.velocity.y * 2 - 0.5 * 9.8 // 重力效果
},
opacity: p.opacity - 0.02,
size: p.size * 0.95
}))
})
}
private createParticle(index: number): Particle {
const angle = (index / 20) * 2 * Math.PI
const speed = 3 + Math.random() * 3
return {
id: index.toString(),
size: 3 + Math.random() * 4,
color: this.getRandomParticleColor(),
position: { x: 0, y: 0 },
velocity: {
x: Math.cos(angle) * speed,
y: Math.sin(angle) * speed
},
opacity: 0.8 + Math.random() * 0.2
}
}
private getRandomParticleColor(): Color {
const colors = [
Color.Red,
Color.Pink,
Color.Yellow,
Color.Orange,
Color.Magenta
]
return colors[Math.floor(Math.random() * colors.length)]
}
private syncLikeState() {
// 通过分布式数据管理同步状态
distributedData.sync('advanced_like', {
isLiked: this.isLiked,
timestamp: new Date().getTime(),
particles: this.isLiked ? this.particles : []
})
}
}
interface Particle {
id: string;
size: number;
color: Color;
position: Position;
velocity: Velocity;
opacity: number;
}
interface Position {
x: number;
y: number;
}
interface Velocity {
x: number;
y: number;
}
3. 跨设备同步实现(Java)
// LikeSyncService.java
public class LikeSyncService extends Ability {
private static final String TAG = "LikeSyncService";
private static final String LIKE_CHANNEL = "like_sync_channel";
private DistributedDataManager dataManager;
private LikeStateListener likeListener;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
initDataManager();
registerLikeListener();
}
private void initDataManager() {
Context context = getContext();
dataManager = DistributedDataManager.getInstance(context);
}
private void registerLikeListener() {
likeListener = new LikeStateListener() {
@Override
public void onLikeStateChanged(String deviceId, boolean isLiked) {
handleLikeStateChange(deviceId, isLiked);
}
};
dataManager.registerListener(LIKE_CHANNEL, likeListener);
}
private void handleLikeStateChange(String deviceId, boolean isLiked) {
HiLog.info(TAG, "设备 " + deviceId + " 点赞状态变化: " + isLiked);
// 在主线程执行UI更新
getUITaskDispatcher().asyncDispatch(() -> {
if (isLiked) {
triggerRemoteLikeAnimation(deviceId);
}
});
}
private void triggerRemoteLikeAnimation(String deviceId) {
// 这里可以触发远程设备的点赞动画
// 实际实现可能需要通过分布式能力发送动画触发指令
HiLog.info(TAG, "触发设备 " + deviceId + " 的点赞动画");
}
public void syncLikeState(boolean isLiked) {
Map<String, Object> likeData = new HashMap<>();
likeData.put("isLiked", isLiked);
likeData.put("timestamp", System.currentTimeMillis());
dataManager.syncData(LIKE_CHANNEL, likeData);
}
@Override
public void onStop() {
super.onStop();
if (dataManager != null && likeListener != null) {
dataManager.unregisterListener(LIKE_CHANNEL, likeListener);
}
}
}
interface LikeStateListener {
void onLikeStateChanged(String deviceId, boolean isLiked);
}
三、动画参数详解
1. 动画曲线对比
| 曲线类型 | 描述 | 适用场景 |
|---|---|---|
Curve.EaseIn |
动画开始时慢,然后加速 | 元素离开屏幕 |
Curve.EaseOut |
动画开始时快,然后减速 | 元素进入屏幕 |
Curve.EaseInOut |
动画开始和结束都慢 | 大多数状态变化 |
Curve.Linear |
匀速运动 | 需要一致速度的动画 |
Curve.Spring |
弹性效果 | 有弹性的交互元素 |
Curve.Friction |
摩擦减速效果 | 粒子系统、自然运动 |
2. 动画参数配置
// 动画配置示例
animateTo({
duration: 300, // 动画持续时间(ms)
curve: Curve.EaseInOut, // 动画曲线
delay: 100, // 延迟开始时间(ms)
iterations: 1, // 重复次数(无限循环可设置-1)
playMode: PlayMode.Normal // 播放模式(Normal/Reverse/Alternate)
}, () => {
// 动画内容
this.scaleValue = 1.2
this.bgColor = Color.Pink
})
四、使用示例
1. 在游戏界面中使用点赞按钮
// GameScene.ets
import { LikeButton, AdvancedLikeButton } from './LikeButton'
@Entry
@Component
struct GameScene {
@State playerLikes: number = 0
build() {
Column() {
// 玩家头像和昵称
PlayerInfo()
// 游戏内容
GameContent()
// 点赞区域
this.buildLikeSection()
}
}
@Builder
buildLikeSection() {
Row() {
Text(`点赞数: ${this.playerLikes}`)
.fontSize(16)
AdvancedLikeButton()
.onLikeChanged((isLiked) => {
if (isLiked) {
this.playerLikes++
} else {
this.playerLikes--
}
})
}
.margin({ top: 20 })
}
}
@Component
struct PlayerInfo {
@State playerName: string = '游戏玩家'
@State avatar: Resource = $r('app.media.default_avatar')
build() {
Row() {
Image(this.avatar)
.width(60)
.height(60)
.borderRadius(30)
Text(this.playerName)
.fontSize(18)
.margin({ left: 10 })
}
}
}
2. 跨设备同步测试代码
// LikeSyncTest.ets
@Entry
@Component
struct LikeSyncTest {
@State localLike: boolean = false
@State remoteLike: boolean = false
@State devices: string[] = ['设备1', '设备2', '设备3']
build() {
Column() {
Text('跨设备点赞同步测试')
.fontSize(20)
.margin(10)
// 本地设备状态
this.buildLocalDevice()
// 远程设备状态
ForEach(this.devices, (device) => {
this.buildRemoteDevice(device)
})
}
}
@Builder
buildLocalDevice() {
Column() {
Text('当前设备')
.fontSize(16)
LikeButton({ isLiked: this.localLike })
.onClick(() => {
this.localLike = !this.localLike
// 模拟同步到其他设备
this.syncToAllDevices(this.localLike)
})
}
.padding(10)
.borderRadius(8)
.backgroundColor('#F0F0F0')
.margin(5)
}
@Builder
buildRemoteDevice(device: string) {
Column() {
Text(device)
.fontSize(16)
LikeButton({ isLiked: this.remoteLike })
}
.padding(10)
.borderRadius(8)
.backgroundColor('#F5F5F5')
.margin(5)
}
private syncToAllDevices(isLiked: boolean) {
// 模拟网络延迟
setTimeout(() => {
this.remoteLike = isLiked
}, 300)
}
}
五、性能优化建议
- 减少动画复杂度:避免同时运行过多动画
- 使用硬件加速:对opacity和transform属性动画性能更好
- 合理使用will-change:提前告知浏览器哪些属性会变化
- 避免布局抖动:动画中避免触发布局重新计算
- 适当降低帧率:非关键动画可使用较低帧率
// 性能优化示例
@Component
struct OptimizedLikeButton {
@State isLiked: boolean = false
build() {
// 使用will-change优化
Column()
.willChange({ opacity: true, transform: true })
{
Button() {
Image(this.isLiked ? $r('app.media.liked') : $r('app.media.unliked'))
}
.onClick(() => {
// 使用轻量级动画
animateTo({
duration: 200,
curve: Curve.EaseOut
}, () => {
this.isLiked = !this.isLiked
})
})
}
}
}
通过以上实现,我们创建了一个高性能、跨设备同步的点赞按钮动画组件,可以在鸿蒙跨设备游戏场景中提供一致的用户体验。
更多推荐

所有评论(0)