语音房礼物动画:把 SVGA 和 MP4 接进同一套播放流程

语聊房的动画不只是一段好看的素材。礼物会连续到达,头像和昵称要替换,网络可能中断,用户也会切房或退到后台。我维护这部分代码时,更关心这些情况能否被同一套业务规则接住。

舒翱移动端 / 全栈 / Agent 应用

先分清素材和业务

这个项目的礼物播放层同时接入了 SVGA 和基于 VAP 的 MP4 动效。收到资源后,业务层按格式进入不同播放器,但排队、当前是否播放以及后续推进仍由上层管理。对页面而言,关心的是当前这条效果能不能展示、何时结束,而不是每种格式各自怎样组织解码和渲染。

SVGA 这一路需要先解析素材,取得动画对象,再交给播放器。现有实现把一次性礼物设为播放一遍,结束后清理画面并移除视图。循环装饰的需求不同,不能照搬“一遍播完”的设置。比如等待队列依赖完成通知推进,如果拿一个无限循环的素材当一次性礼物使用,后面的内容就可能一直等不到机会。这是格式参数和业务状态需要一起检查的地方。

VAP 用视频形式承载透明动效,并支持把头像、昵称等内容放进素材预留的位置。我不会只根据文件大小判断哪一种更合适:还要看设计交付的格式、动态替换要求、显示尺寸、设备表现和维护成本。已有项目要考虑存量素材,换播放器意味着资源和展示规则也要一起验证,不能把 SDK 替换当成单纯的依赖升级。

把加载路径和动态内容接稳

项目里的 MP4 资源有包内文件、沙盒缓存和远程下载几条入口。封装先寻找已有文件,确实需要下载时再异步获取,准备好以后交给播放器。对维护来说,每条入口都要走通相同的完成和失败通知:同一份素材首次打开和再次打开,差别应该只是是否需要下载,业务层不能因为命中了缓存就收不到结束事件。

素材中的动态内容也需要一个明确约定。当前做法是把头像、昵称等数据组成字典,播放器按资源标签取对应值;需要网络图片时,通过图片加载组件查询缓存或下载后返回。这样动画文件负责位置、运动和视觉,业务负责提供这一次展示的数据。接入新素材时,我会先核对标签是否对应、空值如何处理,再查为什么画面里少了头像或昵称。

有些“偶尔不显示”的问题只出现在特定路径:本地有文件时正常,重新下载后不正常;文字替换正常,图片回调却没有结果。我的检查顺序是先确认资源来源、解析结果和回调是否返回,再看布局及层级。这样能把数据问题和渲染问题分开,避免一看到空白就先调整约束,最后改了页面却没有碰到真正的分支。

失败也必须让队列往前走

现有礼物播放层维护等待数组和播放状态。普通礼物追加到队尾,优先展示的入场效果插到等待队列前面;当前没有播放内容时,才启动下一条。这是对展示顺序的管理,并不等于所有动画组件只能存在一个实例。房间里还会同时出现气泡、轨迹和跑马灯,它们各有自己的展示范围和层级。

我最在意的情况,是某份资源出错后,队列还能不能继续。当前代码把解析失败、空结果和播放失败接到收尾处理,复位播放状态、移除当前展示,然后尝试下一条。如果只把错误打印出来,播放中的标记仍为真,业务看上去就像“后面的礼物都没收到”。这时首先要检查状态有没有归还,而不是马上怀疑 Socket 消息丢失。

层级和点击区域也属于播放功能。项目里礼物效果、轨迹、气泡和跑马灯有明确的前后关系,展示视图默认不接收点击,需要跳转的内容另外设置点击区域。跑马灯结束或停止时同步移除这个区域,避免透明按钮继续挡住麦位或工具栏。动画看起来正常,只能说明画面出现了,还需要确认它没有影响用户正在做的操作。

一次性礼物和循环装饰分别收尾

一次性礼物已经过去,回到前台重新播放通常没有必要。当前礼物播放层在应用失去活跃状态时停止展示并清理等待内容;一次性 MP4 也不会走循环恢复逻辑。头像装饰、背景等持续效果则需要记住素材和播放状态,回到前台时确认视图仍在窗口中,再决定是否恢复。是否继续播放,应该由这段效果的用途决定。

项目的通用动画视图会为 SVGA 保存离开前的帧和播放状态;MP4 则保留文件路径、循环设置及是否允许恢复。主动停止还会关闭自动恢复标记,避免用户已经结束展示,随后一次前台通知又把它拉起来。这里的“暂停”“主动停止”和“自然播放完成”有不同含义,业务层要知道哪一种结束允许推进下一条,哪一种需要直接清空。

我会把首次下载、缓存命中、资源失败、连续到达、切房和前后台切换分别验证。缓存能减少重复加载,也会保留资源;单个素材播放流畅,也不能证明连续播放时的峰值内存可接受。对于新项目,还要重新评估依赖维护情况:SVGA 旧版 iOS 仓库已经归档,VAP 官方仓库也声明停止更新。已有封装能继续服务当前业务,但后续系统适配和素材迁移成本需要单独考虑。

延伸阅读

Talka Logo对应项目Talka
返回全部文章

搜索项目和文章

输入关键词,查找项目或文章。

使用 Tab 选择结果,按 Esc 关闭。