做了这么久的Flutter音乐播放器App,从音频播放、本地扫描一路做到歌单、排行榜、搜索,功能一点点堆起来还挺有成就感。这一篇是系列的第18篇,主题很直接:给App加上MV列表。光看名字觉得简单,无非就是视频列表嘛,但真在OpenHarmony设备上跑起来,才发现坑比想象中多不少。如果你正在用Flutter适配OpenHarmony做音视频类功能,或者想把一个纯音乐App升级成带MV能力的版本,这篇实战记录能帮你少走几个弯路。
这里说的MV列表,是音乐App里那种展示音乐视频资源的列表页,一般包含封面图、歌曲名、歌手、时长、播放量等核心信息,点击后进入全屏播放。本文不会只讲UI怎么画,而是会聚焦三件事:第一,MV列表和普通歌曲列表在设计思路上有什么不同;第二,数据层、分页加载和视频播放器怎么组装起来;第三,在OpenHarmony上跑Flutter视频功能时会遇到的兼容性和性能问题,以及我的排查解法。
1. 先想清楚再做:MV列表的整体设计思路
1.1 MV列表和普通歌曲列表的差异
做MV列表之前,我先把普通歌曲列表的实现重新审视了一遍。纯音频列表的信息密度很高,一行就能放标题、歌手、专辑、时长,用户扫一眼就能定位到目标。但MV列表不一样,它的核心视觉元素是封面视频或封面图,而不是文字,所以列表项的布局必须重新设计,不能直接把原来的ListTile换成大图就完事。
设计上有个关键差异需要提前感知:列表项尺寸变大了。普通列表的每一项可能只有60~80像素高,一个屏幕上能显示十几项;但MV列表的卡片普遍是16:9的视频封面加文字区域,单卡高度至少200像素左右。可复用的可见项数量会减少,但每一项的构建成本增加了,这对Flutter的build效率和图片加载策略提出了更高的要求。
另外,MV卡片的信息层级通常是这样的:封面图是第一视觉焦点,其次是歌名,再是歌手和播放量,时长角标则叠在封面角落。这种层级关系和音乐列表完全不同,不能直接把原来的数据模型塞进新页面了事。
交互上也有一个核心分歧点:MV列表点击后是直接全屏播放,还是先进入一个详情页?我当时权衡之后选择了点击卡片直接进入全屏播放页,理由是音乐App的MV功能主要目的是快速消费视频内容,中间夹一个详情页反而增加操作成本。后续如果要加MV评论、点赞等社交功能,再单独拆详情页也不迟。
1.2 播放器插件在OpenHarmony上的选型
MV列表最核心的技术决策是播放器选型。Flutter生态里视频播放方案大概有四条路:官方维护的video_player、基于video_player二次封装的chewie、社区比较新的media_kit,以及完全自己写PlatformView去调原生播放能力。
我在OpenHarmony这个特定平台上做了取舍。media_kit虽然性能表现不错,很多桌面端的Flutter项目都在用,但它的原生依赖比较复杂,在OpenHarmony上的兼容性缺乏足够多的实践验证,贸然引入风险较大。chewie本质上是一个补充了控制条、进度条等UI的video_player包,考虑到播放器控制UI我想自己定制,所以没有选它。
最终我选择的是官方维护的video_player插件。理由有三:一是它的API稳定,官方长期维护,遇到问题能找到的参考资料最多;二是它对底层播放能力的封装相对简洁,适配到OpenHarmony时只要底层AVPlayer能力打通,上层基本不用大改;三是它能满足当前阶段的全部需求——创建一个VideoPlayerController、初始化、播放、暂停、跳转进度,这些核心能力完全覆盖。
至于自己写PlatformView原生方案,我能说这条路很硬核但真的费时。要在OpenHarmony侧掌握AVPlayer的完整调用链,还要处理Flutter与原生之间的纹理共享、生命周期同步、事件回调,工程量比在Android上做同样的事更大。除非团队里有熟悉OpenHarmony原生开发的人,否则不建议从零开始。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据层与状态管理:让列表先跑起来
2.1 MV数据结构设计
先设计MV的数据模型。我的建议是不要为了省事把所有字段都塞进一个Map里,而是建一个明确的实体类,后面加字段、做序列化都会方便很多。MvItem我设计了这些字段:
dart复制class MvItem {
final String id; // MV唯一ID
final String t
