如何实现Expo-AV视频在FlatList聚焦时自动播放及多视频处理
FlatList中视频自动播放/暂停实现方案及多视频可见时的播放策略
一、实现视频进入视图自动播放、移出暂停的方案
核心思路
利用React Native FlatList的视图可见性监听功能,结合视频组件的播放控制API,实现视频进入可见范围时自动播放、移出时暂停的逻辑。
具体实现步骤
依赖准备
使用react-native-video作为视频播放组件(也可使用RN官方Video组件),安装命令:npm install react-native-video配置视图可见性规则
通过viewabilityConfig定义“视频进入可见范围”的判定标准,比如设置可见比例≥50%时触发状态变更:const viewabilityConfig = { itemVisiblePercentThreshold: 50, // 可见比例达到50%即视为可见 };监听可见项变化并控制播放
通过FlatList的onViewableItemsChanged回调,获取当前可见的视频项,对比之前的播放状态,完成播放/暂停的切换:完整代码示例:
import React, { useRef, useState } from 'react'; import { FlatList, View, Dimensions } from 'react-native'; import Video from 'react-native-video'; const { height: screenHeight } = Dimensions.get('window'); const viewabilityConfig = { itemVisiblePercentThreshold: 50, }; const MediaFeed = () => { // 存储每个视频组件的ref,用于控制播放状态 const videoRefs = useRef({}); // 记录当前正在播放的视频ID const [playingId, setPlayingId] = useState(null); const handleViewableItemsChanged = ({ viewableItems, changed }) => { // 暂停所有刚移出可见范围的视频 changed.forEach(item => { if (!item.isViewable && item.item.id === playingId) { videoRefs.current[item.item.id]?.pause(); setPlayingId(null); } }); // 找到第一个可见的视频进行播放 const targetVideo = viewableItems.find(item => item.item.type === 'video'); if (targetVideo && targetVideo.item.id !== playingId) { // 先暂停之前正在播放的视频 if (playingId) { videoRefs.current[playingId]?.pause(); } // 播放当前目标视频 videoRefs.current[targetVideo.item.id]?.play(); setPlayingId(targetVideo.item.id); } }; // 模拟媒体数据(实际从接口获取) const mediaData = [ { id: '1', type: 'image', url: 'xxx' }, { id: '2', type: 'video', url: 'xxx' }, { id: '3', type: 'image', url: 'xxx' }, { id: '4', type: 'video', url: 'xxx' }, ]; const renderItem = ({ item }) => { if (item.type === 'image') { return ( <View style={{ height: screenHeight, justifyContent: 'center', alignItems: 'center' }}> {/* 渲染图片组件 */} </View> ); } return ( <View style={{ height: screenHeight }}> <Video ref={ref => videoRefs.current[item.id] = ref} source={{ uri: item.url }} style={{ flex: 1 }} resizeMode="cover" paused={playingId !== item.id} // 仅当前播放ID匹配时不暂停 /> </View> ); }; return ( <FlatList data={mediaData} renderItem={renderItem} keyExtractor={item => item.id} viewabilityConfig={viewabilityConfig} onViewableItemsChanged={handleViewableItemsChanged} pagingEnabled // 若为全屏上下滑动的feed流,开启分页更符合交互习惯 /> ); }; export default MediaFeed;
关键细节说明
- 如果是类似抖音的全屏滑动feed流,开启
pagingEnabled可以让滑动体验更流畅,且每个item刚好占满屏幕,避免多个视频同时可见的情况。 - 可根据需求调整
itemVisiblePercentThreshold的值,比如设置为100则视频完全可见时才播放。
二、多个视频同时完全可见时的播放策略
针对多个视频同时完全可见的场景,推荐以下几种主流策略,可根据产品需求选择:
- 优先播放最顶部的可见视频
这是内容类APP最常用的逻辑,符合用户从上到下浏览的习惯,比如用户滚动后,顶部先进入视野的视频自动播放。 - 播放最近滚动进入视野的视频
记录用户滚动过程中最后一个进入可见范围的视频,优先播放它,适合快速滚动后的场景。 - 用户手动触发播放
默认所有视频暂停,用户点击哪个视频再播放哪个,适合对流量敏感或希望用户自主控制的产品。
其中优先播放顶部可见视频是最符合大众交互预期的选择,能避免播放逻辑混乱,提升用户体验。
内容的提问来源于stack exchange,提问作者Ryan Wang
相关产品推荐
相关产品推荐

