Search code examples
react-nativereact-native-flatlistreact-native-video

Pausing videos on FlatList horizontal when swiping


I'm able to console log the viewable items, when swiping when using FlatList, but I was wondering how I can manage pausing the video. Or if there's a better way in doing so?

This is the RenderItem function component

const RenderItem = (props) => {
  const [paused, setPaused] = useState(true);

  const togglePlay = () => setPaused(prev => !prev);

  return (
    <View>
      {props.is_video ? (
        <>
          <Video
            paused={paused}
            repeat
            source={{uri: props.mediaUrl}}
          />
          <TouchableWithoutFeedback onPress={togglePlay}>
            <View>
                {paused ? <Icon
                size={180}
                name="play"
                type="FontAwesome"
                style={{opacity: 0.7, color: '#cccccc'}}
              /> : null}
            </View>
          </TouchableWithoutFeedback>
        </>
      ) : (
        <Image source={{uri: props.mediaUrl}} />
      )}
    </View>
  );
};

Then in another function, I have this:

const Post = (props) => {

  const onViewRef = useRef((viewableItems)=> {console.log(viewableItems)});
  const viewConfigRef = useRef({ viewAreaCoveragePercentThreshold: 50 });

  return (
    <View style={{flex: 1}}>
      <View>
        <FlatList
          onViewableItemsChanged={onViewRef.current}
          viewabilityConfig={viewConfigRef.current}
          data={props.navigation.state.params.media}
          snapToAlignment={'center'}
          horizontal
          decelerationRate={'fast'}
          pagingEnabled
          renderItem={({item}) => <RenderItem {...item} />}
          keyExtractor={item => item.mediaUrl}
        />
      </View>
    </View>
  );
};

I'm able to press the video and it'll Play or Pause. When I'm swiping right now, the videos continue to play. I want to be able to ensure that when swiping, the video played will become paused now.


Solution

  • You can lift the pause/playing state to the parent component (Post). Since at most 1 video should be playing at anytime, the state can simply store the item ID (or mediaUrl if you are using that as the key/ID) that is currently playing.

    In RenderItem:

    <Video paused={props.paused} ... />
    <TouchableWithoutFeedback onPress={props.onTogglePlay}>
    

    In Post (you can use useCallback for the anonymous functions):

    const [activeVideo, setActiveVideo] = useState(null);
    ...
    <FlatList onViewableItemsChanged={() => setActiveVideo(null)} .../>
    ...
    <RenderItem 
      paused={activeVideo !== item.mediaUrl} 
      onTogglePlay={() =>
        setActiveVideo(item.mediaUrl === activeVideo ? null : item.mediaUrl)
      }
      {...item}
    />
    

    You may also store the ref to the active video and pause the video through that ref.