You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native长列表如何检测屏幕可见卡片?实现类似Instagram视频自动播放

Answer

Hey there! Great question—detecting visible list items in React Native for auto-playing videos (just like Instagram) is a super common use case, and luckily there’s an official, cross-platform solution that replaces Android’s getFirstVisiblePosition()/getLastVisiblePosition(). Let’s break down how to implement it:

1. Use FlatList’s onViewableItemsChanged Prop

React Native’s FlatList (the modern replacement for the deprecated ListView) comes with a built-in prop called onViewableItemsChanged that fires whenever the set of visible items changes. This is exactly what you need to track which cards are active on screen.

First, you’ll define a viewabilityConfig to specify what counts as an "active" (visible) item. For example, you can set a threshold like 70% of the item being visible to trigger playback.

Full Example Implementation

Here’s a complete working example with cards and video playback logic:

import React, { useState, useRef } from 'react';
import { View, FlatList, Card, Text, StyleSheet } from 'react-native';
import Video from 'react-native-video'; // Use this library for video playback

const VideoFeed = () => {
  const [visibleItemKeys, setVisibleItemKeys] = useState([]);
  const videoRefs = useRef({}); // Store refs to each video component

  // Define when an item is considered "viewable"
  const viewabilityConfig = {
    viewAreaCoveragePercentThreshold: 70, // Item is visible if 70% of it is on screen
    waitForInteraction: false, // Trigger immediately without waiting for user input
  };

  // Update visible items list when scroll changes
  const handleViewableItemsChanged = ({ viewableItems }) => {
    setVisibleItemKeys(viewableItems.map(item => item.key));
  };

  // Auto-play videos when scrolling stops
  const handleScrollEnd = () => {
    // Play visible videos
    visibleItemKeys.forEach(key => {
      videoRefs.current[key]?.play();
    });
    // Pause videos that are no longer visible
    Object.keys(videoRefs.current).forEach(key => {
      if (!visibleItemKeys.includes(key)) {
        videoRefs.current[key]?.pause();
      }
    });
  };

  const renderCard = ({ item }) => (
    <Card style={styles.card}>
      <Video
        ref={ref => videoRefs.current[item.key] = ref}
        source={{ uri: item.videoUrl }}
        style={styles.video}
        paused={true} // Start all videos paused
        resizeMode="cover"
      />
      <Text style={styles.caption}>{item.caption}</Text>
    </Card>
  );

  // Sample feed data
  const feedData = [
    { key: '1', videoUrl: 'https://example.com/video1.mp4', caption: 'First post' },
    { key: '2', videoUrl: 'https://example.com/video2.mp4', caption: 'Second post' },
    { key: '3', videoUrl: 'https://example.com/video3.mp4', caption: 'Third post' },
    // Add more items here...
  ];

  return (
    <FlatList
      data={feedData}
      renderItem={renderCard}
      keyExtractor={item => item.key}
      viewabilityConfig={viewabilityConfig}
      onViewableItemsChanged={handleViewableItemsChanged}
      onScrollEndDrag={handleScrollEnd} // Trigger play when user stops scrolling
      onMomentumScrollEnd={handleScrollEnd} // Also trigger when scroll slows to a stop
      decelerationRate="fast" // Match Instagram's smooth scroll feel
    />
  );
};

const styles = StyleSheet.create({
  card: {
    marginVertical: 8,
    marginHorizontal: 16,
    borderRadius: 12,
    overflow: 'hidden',
  },
  video: {
    height: 350,
    width: '100%',
  },
  caption: {
    padding: 14,
    fontSize: 14,
    color: '#333',
  },
});

export default VideoFeed;

2. If You’re Using a Custom List Component (Like NativeBase’s <List>)

If you’re working with a library component like NativeBase’s <List>, check if it wraps FlatList under the hood. Most modern list libraries allow passing through FlatList props directly. For example:

import { List } from 'native-base';

<List
  dataArray={feedData}
  renderItem={renderCard}
  viewabilityConfig={viewabilityConfig}
  onViewableItemsChanged={handleViewableItemsChanged}
  onScrollEndDrag={handleScrollEnd}
/>

If the component doesn’t expose these props, switching to FlatList directly will give you more control over visibility tracking.

3. Key Tips for Instagram-Like Behavior

  • Adjust Viewability Threshold: Tweak viewAreaCoveragePercentThreshold to match your needs—set it higher (like 80%) if you only want videos to play when most of the card is visible.
  • Optimize Video Playback: Always pause videos when they leave the viewport to save bandwidth and battery life. Using a ref map ensures you can control each video individually.
  • Handle All Scroll Scenarios: Use both onScrollEndDrag (when user lifts their finger) and onMomentumScrollEnd (when scroll slows to a stop) to cover all cases where scrolling stops.

This approach is the official React Native solution and works consistently across both iOS and Android, no native module hacks required.

内容的提问来源于stack exchange,提问作者S.Hossein Asadollahi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:10:33