Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pause video in flatlist when out of view

I have a flatlist showing videos. I want that when a video goes out of the view it should be paused. I am maintaining the pause state in each of the Posts component.

class Posts extends React.PureComponent {

constructor() {
 super()
 this.state = {
   pause: true,
 }

 return(){
  <Video
    pause={this.state.pause}
    //other props
  />
 }

}

I am using react-native-video.

I have tried using onViewableItemsChanged prop of Flatlist but it doesn't change the state.

I tried this . But it doesn't seem to work for me.

How should I proceed ?

like image 569
Mayank Raj Avatar asked Feb 23 '19 09:02

Mayank Raj


1 Answers

Here is a possible solution using react-native-inviewport. This dependency is only a single index file that contains a component that has a callback when view is in the viewport. It could easily be modified to suit your needs.

I have constructed a very simple app that has a FlatList. The 11th item in the FlatList is a video. That should mean that the video is off the screen when the App renders so the viddeo won't be playing, once the video comes fully into the viewport it should then start playing.

App.js

import * as React from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
import VideoPlayer from './VideoPlayer';

export default class App extends React.Component {

  state = {
    data: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
  }

  renderItem = ({item, index}) => {
    if (index === 10) {
      return <VideoPlayer />
    } else {
      return (
        <View style={{height: 100, backgroundColor: '#336699', justifyContent: 'center', alignItems: 'center'}}>
          <Text>{index}</Text>
        </View>
      )
    }
  }
  keyExtractor = (item, index) => `${index}`;

  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={this.state.data}
          renderItem={this.renderItem}
          keyExtractor={this.keyExtractor}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  }
});

VideoPlayer.js

This is a component that contains the Video component. The video is wrapped in the InViewPort component that has a callback function. The callback returns true when the component it surrounds is completely in the viewport and false when it is not fully in the viewport. The callback calls this.handlePlaying which in turn calls either this.playVideo or this.pauseVideo depending on the boolean value.

import React, {Component} from 'react';
import { View, StyleSheet } from 'react-native';
import { Video } from 'expo-av';
import InViewPort from './InViewPort';
//import InViewPort from 'react-native-inviewport; // this wouldn't work in the snack so I just copied the file and added it manually.

export default class VideoPlayer extends React.Component {

  pauseVideo = () => {
    if(this.video) {
      this.video.pauseAsync();
    }
  }

  playVideo = () => {
    if(this.video) {
      this.video.playAsync();
    }
  }

  handlePlaying = (isVisible) => {
    isVisible ? this.playVideo() : this.pauseVideo();
  }

  render() {
      return (
        <View style={styles.container}>
         <InViewPort onChange={this.handlePlaying}>
          <Video
            ref={ref => {this.video = ref}}
            source={{ uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4' }}
            rate={1.0}
            volume={1.0}
            isMuted={false}
            resizeMode="cover"
            shouldPlay
            style={{ width: 300, height: 300 }}
          />
          </InViewPort>
        </View>
      )
  }  
}

const styles = StyleSheet.create({
  container: {
    justifyContent: 'center',
    alignItems: 'center'
  }
});

Here is a snack showing it working https://snack.expo.io/@andypandy/video-only-playing-when-in-viewport

I should point out that if the video is not fully in the viewport then it will not play. I am sure some tweaking could be done to react-native-inviewport so that it would play the video if it was partially in the viewport if that is what you wanted, perhaps by passing the height of the video to the InViewPort component.

like image 100
Andrew Avatar answered Oct 13 '22 14:10

Andrew