在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

发布于:2025-06-11 ⋅ 阅读:(22) ⋅ 点赞:(0)

下面我将详细介绍如何使用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. 实际项目注意事项

  1. ​性能优化​​:

    • 使用LazyForEach加载视频列表
    • 视频预加载机制
    • 动画使用硬件加速
  2. ​网络请求​​:

    • 实现点赞API接口
    • 添加请求重试机制
    • 处理网络异常情况
  3. ​用户体验​​:

    • 添加加载状态指示器
    • 实现点赞操作的防抖处理
    • 离线状态下的点赞处理
  4. ​安全考虑​​:

    • 点赞操作的身份验证
    • 防止重复点赞
    • 数据加密传输
  5. ​测试要点​​:

    • 双击手势的灵敏度测试
    • 动画性能测试
    • 多设备同步测试
  6. ​扩展功能​​:

    • 点赞列表查看
    • 点赞通知功能
    • 热门点赞视频推荐

通过以上实现,你可以在HarmonyOS 5应用中创建类似抖音的点赞功能,包括基础点赞、双击点赞、动画效果和数据同步等核心功能。