在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。
1. 基础点赞功能实现
1.1 创建数据模型
// VideoModel.ets
export class VideoModel {id: string = "";title: string = "";author: string = "";coverUrl: string = "";videoUrl: string = "";likes: number = 0;isLiked: boolean = false;comments: number = 0;shares: number = 0;
}
1.2 点赞按钮组件
// LikeButton.ets
@Component
export struct LikeButton {@Prop video: VideoModel;@State private isAnimating: boolean = false;build() {Column() {// 点赞按钮Image(this.video.isLiked ? $r('app.media.ic_liked') : $r('app.media.ic_like')).width(40).height(40).scale({ x: this.isAnimating ? 1.2 : 1, y: this.isAnimating ? 1.2 : 1 }).animation({ duration: 200, curve: Curve.EaseInOut }).onClick(() => {this.handleLike();})// 点赞数Text(this.video.likes.toString()).fontSize(14).fontColor(Color.White).margin({ top: 4 })}.alignItems(HorizontalAlign.Center)}private handleLike() {// 触发动画this.isAnimating = true;setTimeout(() => {this.isAnimating = false;}, 200);// 更新点赞状态this.video.isLiked = !this.video.isLiked;this.video.likes += this.video.isLiked ? 1 : -1;// 这里可以添加网络请求,同步点赞状态到服务器this.syncLikeStatus();}private syncLikeStatus() {// 实际项目中这里应该调用API同步点赞状态console.log(`视频${this.video.id}点赞状态: ${this.video.isLiked}`);}
}
2. 双击点赞功能实现
2.1 视频组件封装
// VideoPlayer.ets
@Component
export struct VideoPlayer {@Prop video: VideoModel;@State private showLikeAnimation: boolean = false;private lastTapTime: number = 0;build() {Stack() {// 视频播放器Video({src: this.video.videoUrl,controller: new VideoController()}).width('100%').height('100%').objectFit(ImageFit.Cover).onTouch((event: TouchEvent) => {if (event.type === TouchType.Down) {this.handleTap();}})// 点赞动画if (this.showLikeAnimation) {Image($r('app.media.ic_liked')).width(80).height(80).position({ x: '50%', y: '50%' }).scale({ x: 0, y: 0 }).opacity(1).animation({duration: 1000,curve: Curve.EaseOut,onFinish: () => {this.showLikeAnimation = false;}}).scale({ x: 1.5, y: 1.5 }).opacity(0)}// 右侧互动栏Column() {LikeButton({ video: this.video }).margin({ bottom: 20 })// 其他互动按钮(评论、分享等)...}.position({ x: '85%', y: '50%' })}.width('100%').height('100%')}private handleTap() {const currentTime = new Date().getTime();const timeDiff = currentTime - this.lastTapTime;if (timeDiff < 300) { // 双击判定if (!this.video.isLiked) {this.video.isLiked = true;this.video.likes += 1;this.showLikeAnimation = true;this.syncLikeStatus();}}this.lastTapTime = currentTime;}private syncLikeStatus() {// 同步点赞状态到服务器console.log(`视频${this.video.id}通过双击点赞`);}
}
3. 点赞动画优化
3.1 粒子爆炸效果
// ParticleLikeAnimation.ets
@Component
export struct ParticleLikeAnimation {@State private particles: { id: number, x: number, y: number, scale: number, opacity: number }[] = [];private particleCount: number = 12;build() {Stack() {ForEach(this.particles, (particle) => {Image($r('app.media.ic_liked')).width(20).height(20).position({ x: `${particle.x}%`, y: `${particle.y}%` }).scale({ x: particle.scale, y: particle.scale }).opacity(particle.opacity)})}}public startAnimation() {this.particles = [];// 生成粒子for (let i = 0; i < this.particleCount; i++) {this.particles.push({id: i,x: 50,y: 50,scale: 0,opacity: 1});}// 动画效果this.particles.forEach((particle, index) => {const angle = (index * (360 / this.particleCount)) * (Math.PI / 180);const distance = 15 + Math.random() * 10;setTimeout(() => {particle.x = 50 + Math.cos(angle) * distance;particle.y = 50 + Math.sin(angle) * distance;particle.scale = 0.5 + Math.random() * 0.5;particle.opacity = 0;}, index * 50);});setTimeout(() => {this.particles = [];}, 1000);}
}
3.2 在VideoPlayer中使用粒子动画
// 修改VideoPlayer.ets
@Component
export struct VideoPlayer {@State private particleAnimRef: ParticleLikeAnimation | null = null;build() {Stack() {// ...其他组件// 替换原来的点赞动画ParticleLikeAnimation({ ref: this.particleAnimRef })// ...其他组件}}private handleTap() {const currentTime = new Date().getTime();const timeDiff = currentTime - this.lastTapTime;if (timeDiff < 300) { // 双击判定if (!this.video.isLiked) {this.video.isLiked = true;this.video.likes += 1;this.particleAnimRef?.startAnimation();this.syncLikeStatus();}}this.lastTapTime = currentTime;}
}
4. 数据持久化与同步
4.1 使用分布式数据服务
// LikeService.ets
import distributedData from '@ohos.data.distributedData';export class LikeService {private kvManager: distributedData.KVManager;private kvStore: distributedData.KVStore;async init() {const config = {bundleName: 'com.example.douyin',userInfo: {userId: 'currentUser',userType: distributedData.UserType.SAME_USER_ID}};this.kvManager = distributedData.createKVManager(config);const options = {createIfMissing: true,encrypt: false,backup: false,autoSync: true,kvStoreType: distributedData.KVStoreType.SINGLE_VERSION};this.kvStore = await this.kvManager.getKVStore('likes_store', options);}async syncLike(videoId: string, isLiked: boolean) {if (!this.kvStore) {await this.init();}try {await this.kvStore.put(videoId, isLiked);await this.kvStore.sync({deviceIds: ['all'],mode: distributedData.SyncMode.PUSH});} catch (error) {console.error('同步点赞状态失败:', JSON.stringify(error));}}async getLikeStatus(videoId: string): Promise<boolean> {if (!this.kvStore) {await this.init();}try {const result = await this.kvStore.get(videoId);return !!result;} catch (error) {console.error('获取点赞状态失败:', JSON.stringify(error));return false;}}
}
4.2 在LikeButton中集成数据服务
// 修改LikeButton.ets
@Component
export struct LikeButton {private likeService: LikeService = new LikeService();aboutToAppear() {this.loadLikeStatus();}private async loadLikeStatus() {const isLiked = await this.likeService.getLikeStatus(this.video.id);this.video.isLiked = isLiked;}private async syncLikeStatus() {await this.likeService.syncLike(this.video.id, this.video.isLiked);}
}
5. 完整视频页面实现
// DouyinPage.ets
@Entry
@Component
struct DouyinPage {@State currentVideoIndex: number = 0;@State videos: VideoModel[] = [{id: "1",title: "第一个视频",author: "创作者1",coverUrl: "resources/cover1.jpg",videoUrl: "resources/video1.mp4",likes: 1234,isLiked: false,comments: 56,shares: 12},// 更多视频...];build() {Stack() {// 视频滑动容器Swiper() {ForEach(this.videos, (video: VideoModel) => {SwiperItem() {VideoPlayer({ video: video })}})}.index(this.currentVideoIndex).autoPlay(false).indicator(false).loop(false).vertical(true).edgeEffect(EdgeEffect.Spring).onChange((index: number) => {this.currentVideoIndex = index;})// 顶部导航Row() {Text("推荐").fontSize(18).fontColor(Color.White).margin({ left: 20 })// 其他导航项...}.width('100%').height(50).position({ x: 0, y: 30 })}.width('100%').height('100%').backgroundColor(Color.Black)}
}
6. 实际项目注意事项
-
性能优化:
- 使用LazyForEach加载视频列表
- 视频预加载机制
- 动画使用硬件加速
-
网络请求:
- 实现点赞API接口
- 添加请求重试机制
- 处理网络异常情况
-
用户体验:
- 添加加载状态指示器
- 实现点赞操作的防抖处理
- 离线状态下的点赞处理
-
安全考虑:
- 点赞操作的身份验证
- 防止重复点赞
- 数据加密传输
-
测试要点:
- 双击手势的灵敏度测试
- 动画性能测试
- 多设备同步测试
-
扩展功能:
- 点赞列表查看
- 点赞通知功能
- 热门点赞视频推荐
通过以上实现,你可以在HarmonyOS 5应用中创建类似抖音的点赞功能,包括基础点赞、双击点赞、动画效果和数据同步等核心功能。