鸿蒙炫酷的动画库——ohos-vap

​​​​​地址:https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Fvap

代码地址:

https://gitcode.com/openharmony-tpc/openharmony_tpc_samples/tree/master/vap

OHOS-VAP

在数字娱乐和在线互动的时代,视觉效果的精美程度直接影响用户体验。OHOS-VAP 是一个基于 OpenHarmony 运用 OpenGL 技术和特殊算法打造的强大动画粒子特效渲染组件。它不仅能够为应用程序提供令人惊叹的动画效果,更为用户创造了一种身临其境的视觉享受。

主要特征

  • 相比Webp, Apng动图方案,具有高压缩率(素材更小)、硬件解码(解码更快)的优点.
  • 相比Lottie,能实现更复杂的动画效果(比如粒子特效)
  • 高性能渲染:凭借 OpenGL 的强大能力,OHOS-VAP 实现了高效的粒子特效渲染,确保流畅的用户体验,适用于各种设备。
  • 易于集成:OHOS-VAP 设计简洁,易于与现有项目集成,帮助开发者快速实现酷炫的动画效果,提升应用的吸引力。
  • 多平台支持:兼容多个设备,无论是手机、平板还是电脑,OHOS-VAP 都能提供一致的视觉效果,助力跨终端应用开发。

应用场景

  • 直播间特效:在各大短视频平台中如抖音,快手,得物,企鹅电竞,利用 OHOS-VAP 为直播间增添炫酷的礼物特效,提升观众的互动体验,增加直播的趣味性。
  • 电商活动推广:在游戏领域及电商平台的活动中,使用 OHOS-VAP 实现令人惊叹的产品展示效果,吸引用户眼球,推动销售转化。
  • 游戏体验提升:为游戏场景增添粒子特效,提升整体游戏体验,让玩家沉浸在更为生动的虚拟世界中。

构建依赖

  • 对于开发人员可以调用this.xComponentContext.play()接口来实现自定义视频传参路径(支持网路URL)

C/C++层目录结构

复制代码
├─include				# 遮罩 融合 渲染器 工具类头文件存放
│  ├─mask
│  ├─mix
│  ├─render
│  └─util
├─manager 				# xcomponent 生命周期管理
├─mask 					# 遮罩的实现
├─mix 					# 融合实现
├─napi					# Napi 层功能的封装
├─render				# 渲染器的实现
├─types   				# 接口声明
│  └─libvap	# so文件接口声明
└─util					# 工具类的实现0

源码下载

  1. 本项目依赖 json 库,通过git submodule引入,下载代码时需加上--recursive参数。

    git clone --recursive https://gitcode.com/openharmony-tpc/openharmony_tpc_samples.git

  2. 开始编译项目。

快速使用

  1. api模式 可参考示例代码 api模式
  2. 组件模式 可参考示例代码 组件模式,使用更便捷

头文件引入

在使用文件中进行头文件的引入

复制代码
import { VAPPlayer,MixData } from '@ohos/vap';

定义 VAPPlayer 组件

复制代码
private vapPlayer: VAPPlayer | undefined = undefined;
@State buttonEnabled: boolean = true; // 该状态为控制按钮是否可以点击
@State src: string = "/storage/Users/currentUser/Documents/1.mp4"; // 该路径可为网络路径

配置网络资源下载路径

复制代码
// 具体使用可参考示例代码
// 获取沙箱路径
let context : Context = getContext(this) as Context
let dir = context.filesDir

界面

复制代码
private xComponentId: string = 'xcomponentId_' + util.generateRandomUUID()
XComponent({
  id: this.xComponentId, // 唯一标识
  type: 'surface',
  libraryname: 'vap'
})
  .onLoad((xComponentContext?: object | Record<string, () => void>) => {
    if (xComponentContext) {
      this.vapPlayer = new VAPPlayer(this.xComponentId)
      this.vapPlayer.setContext(xComponentContext)
      this.vapPlayer.sandDir = dir // 设置存储路径
    }
  })
  .backgroundColor(Color.Transparent)
  .height('100%')
  .visibility(this.buttonEnabled ? Visibility.Hidden: Visibility.Visible)
  .width('80%')

设置视频对齐方式

通过setFitType这个接口设置视频对齐方式(支持FIT_XY,FIT_CENTER,CENTER_CROP)

接口需要在play之前使用

复制代码
this.vapPlayer?.setFitType(fitType)

使用

播放接口 Play 的使用

融合动画信息顺序自定义,需要指定 tag, tag 为视频制作时指定,该信息可通过this.vapPlayer.getVideoInfo(uri)接口获取本地视频信息, 通过this.vapPlayer.getVideoInfoAsync(uri)获取在线视频信息。

当融合信息为字体时,可配置字体的对齐,颜色,大小

复制代码
let opts: Array<MixData> = [{
  tag: 'sImg1',
  imgUri: getContext(this).filesDir + '/head1.png'
}, {
  tag: 'abc',
  txt: "星河Harmony NEXT",
  imgUri: getContext(this).filesDir + '/head1.png'
}, {
  tag: 'sTxt1',
  txt: "星河Harmony NEXT",
  textAlign: this.textAlign,
  fontWeight: this.fontWeight,
  color: this.color
}];
this.buttonEnabled = false;

this.vapPlayer?.play(getContext(this).filesDir + "/vapx.mp4", opts, () => {
  this.buttonEnabled = true;
});

当融合信息是图片时,可以使用本地的png图片或image.PixelMap,若使用image.PixelMap,当前仅支持像素格式为image.PixelMapFormat.RGBA_8888数据。

复制代码
let info = await this.vapPlayer?.getVideoInfoAsync("https://static.mszmapp.com/files/20250530/8d7032c2665096d51ca1736c74753998.mp4")
console.log('getVideoInfo info ' + JSON.stringify(info))
let color = new ArrayBuffer(16);
let colorView = new Int8Array(color);
colorView.set([
// 第一行
  0, 255, 0, 255,    // 左 (绿色)
  255, 255, 0, 255,  // 右 (黄色)

  // 第二行
  0, 255, 0, 255,    // 左 (绿色)
  255, 255, 0, 255   // 右 (黄色)
])

let pixelMap = image.createPixelMapSync({size: {height:2, width: 2}, pixelFormat: image.PixelMapFormat.RGBA_8888})
pixelMap.writeBufferToPixelsSync(color)
let opts: Array<MixData> = []
if (info?.srcInfos !== undefined) {
  for (let s of info?.srcInfos) {
    if (s.type === SrcType.IMG) {
      opts.push({
        tag: s.tag,
        imgUri: pixelMap
      })
    } else if (s.type === SrcType.TXT) {
      opts.push({
        tag: s.tag,
        txt: "星河Harmony NEXT 星河Harmony NEXT",
      })
    }
  }
}
this.buttonEnabled = false;
this.vapPlayer?.play("https://static.mszmapp.com/files/20250530/8d7032c2665096d51ca1736c74753998.mp4", opts, () => {
  LogUtil.info("js get callback")
  this.buttonEnabled = true;
});
暂停的使用
复制代码
this.vapPlayer?.pause()
停止的使用
复制代码
this.vapPlayer?.stop()
异步停止的使用 (StopAsync)
复制代码
this.vapPlayer?.stopAsync('unique_id', 3000).then(() => {
  console.log('停止操作完成');
}).catch((error) => {
  console.error('停止失败:', error);
});

this.vapPlayer?.setStopCompleteCallback(() => {
  console.log('停止操作已成功完成');
});
监听手势
  • 在动画播放过程中点击播放区域,如果点击到融合动画资源,回调会返回该资源(字符串)

  • 接口需要在play之前使用

    this.vapPlayer?.on('click', (state)=>{
    if(state) {
    console.log('js get onClick: ' + state)
    }
    })

监听播放生命周期变化

接口需要在play之前使用

复制代码
this.vapPlayer?.on('stateChange', (state, ret)=>{
  if(state) {
    console.log('js get on: ' + state)
    if(ret)
      console.log('js get on frame: ' + JSON.stringify(ret))
  }
})
  • 回调参数 state 反应当前播放的状态

    enum VapState {
    UNKNOWN,
    READY,
    START,
    RENDER,
    COMPLETE,
    DESTROY,
    FAILED
    }

  • 参数 ret ,当 stateRENDERSTART 返回 AnimConfig 对象

  • 参数 ret ,当 stateFAILED 反应当前的错误码

  • 参数 ret ,其余状态为 undefined

应用退出后台
复制代码
  onPageHide(): void {
    console.log('[LIFECYCLE-Page] onPageHide');
    this.vapPlayer?.stop()
  }

可在页面的生命周期中调用onPageHide方法

兼容老视频(alphaplayer 对称的视频)
复制代码
this.vapPlayer?.setVideoMode(VideoMode.VIDEO_MODE_SPLIT_HORIZONTAL)

对于老视频推荐调用这个接口,接口需要在play之前使用

约束与限制

在下述版本通过

  • DevEco Studio 5.0(5.0.3.810), SDK: API12(5.0.0.60)

权限设置

  • 如果确定视频文件在沙箱中则不必配置

  • 在应用模块的module.json5中添加权限, 例如:entry\src\main\module.json5

  • READ_MEDIA 读取用户目录下的文件(比如 文档); WRITE_MEDIA(下载到用户目录下);INTERNET 下载网络文件

    "requestPermissions": [
    {
    "name": 'ohos.permission.READ_MEDIA',
    "reason": 'string:read_file', "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" } }, { "name": 'ohos.permission.WRITE_MEDIA', "reason": 'string:read_file',
    "usedScene": {
    "abilities": [
    "EntryAbility"
    ],
    "when": "always"
    }
    },
    {
    "name": "ohos.permission.INTERNET"
    }
    ]

编译构建

  • 工程创建成功后,构建请运行 Build -> Build Hap(s)/APP(s) -> build App(s) 选项
  • /entry/build/default/outputs 生成 hap
  • 签名安装生成的 hap

测试demo

点击 Play 按钮,测试动画效果,再次点击进入循环播放

相关推荐
Easonmax10 小时前
基础入门 React Native 鸿蒙跨平台开发:实现一个红绿灯
react native·react.js·harmonyos
AirDroid_cn11 小时前
vivo怎样远程控制华为?手机自带的功能可以实现吗?
华为·智能手机
数通工程师11 小时前
华为ME60设备单用户带宽限速配置全流程
网络·网络协议·tcp/ip·华为
zilikew11 小时前
Flutter框架跨平台鸿蒙开发——丢件上报APP的开发流程
flutter·华为·harmonyos·鸿蒙
工程师华哥11 小时前
2026年新版华为HCIA Datacom题库
网络·华为·hcie·hcia·hcip·华为数通·华为题库工具
晚霞的不甘11 小时前
Flutter for OpenHarmony:迈向专业:购物APP的架构演进与未来蓝图
其他·flutter·架构·fiddler·前端框架·harmonyos
大雷神11 小时前
HarmonyOS智慧农业管理应用开发教程--高高种地--第15篇:地图导航与路线规划
华为·harmonyos
Easonmax11 小时前
基础入门 React Native 鸿蒙跨平台开发:栈操作可视化
react native·react.js·harmonyos
Easonmax11 小时前
基础入门 React Native 鸿蒙跨平台开发:链表操作可视化
react native·链表·harmonyos
AirDroid_cn11 小时前
鸿蒙NEXT:如何拦截第三方应用读取剪贴板内容?
华为·harmonyos