不在视野范围内时暂停平面列表中的视频

Posted

技术标签:

【中文标题】不在视野范围内时暂停平面列表中的视频【英文标题】:Pause video in flatlist when out of view 【发布时间】:2019-02-23 09:01:45 【问题描述】:

我有一个显示视频的平面列表。我希望当视频离开视图时它应该被暂停。我在每个Posts 组件中保持暂停状态。

class Posts extends React.PureComponent 

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

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


我正在使用react-native-video

我曾尝试使用 FlatlistonViewableItemsChanged 属性,但它不会改变状态。

我试过 this 。 但这似乎对我不起作用。

我应该如何进行?

【问题讨论】:

【参考方案1】:

这是使用react-native-inviewport 的可能解决方案。这个依赖只是一个单一的索引文件,它包含一个当视图在视口中时有回调的组件。它可以轻松修改以满足您的需求。

我构建了一个非常简单的应用程序,它有一个 FlatList。 FlatList 中的第 11 项是视频。这应该意味着当应用程序渲染时视频不在屏幕上,因此视频不会播放,一旦视频完全进入视口,它就应该开始播放。

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

这是一个包含视频组件的组件。视频封装在具有回调函数的InViewPort 组件中。当它所包围的组件在视口中完全 时,回调返回 true,当它不完全在视口中时,回调返回 false。回调调用this.handlePlaying,后者又调用this.playVideothis.pauseVideo,具体取决于布尔值。

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'
  
);

这是一个显示它工作的小吃https://snack.expo.io/@andypandy/video-only-playing-when-in-viewport

我应该指出,如果视频没有完全在视口中,那么它就不会播放。我确信可以对react-native-inviewport 进行一些调整,以便如果视频部分在视口中,如果这是您想要的,它可以播放视频,也许通过将视频的高度传递给InViewPort 组件。

【讨论】:

Above 同时播放 flatlist 中的所有视频,而不是一个一个聚焦 它将播放用户完全可见的任何视频。因此,如果您在屏幕上显示三个视频并且完全可见,那么它将播放所有三个视频。您可以更新零食中包含的 InViewPort.js 以定义您所说的“聚焦”的含义,因为它目前检查整个屏幕,但可以对其进行修改以检查屏幕的一部分。 感谢您的回复。问题是它甚至会播放我屏幕上的视频,也就是平面列表底部的视频。我不得不提一下,我没有使用 expo。 这很奇怪,因为它不适合我。 @Andrew 我的平面列表包含所有视频,所以,这使得所有视频都可以播放【参考方案2】:

我就是这样做的 在我的卡片组件里面有 video

<Video ...
    paused=currentIndex !== currentVisibleIndex
/>

currentIndex 和 currentVisibleIndex 都是从 FlatList 父组件传递的

我的 FlatList 将 renderItem 索引作为 currentIndex

传递
<FlatList
    data=[...]
    renderItem=( item, index ) => (
    <GalleryCard
        ...item
        currentIndex=index
        currentVisibleIndex=currentVisibleIndex
        />
        )
    onViewableItemsChanged=this.onViewableItemsChanged
    viewabilityConfig=
        viewAreaCoveragePercentThreshold: 90
    

最后我的这是如何计算 currentVisibleIndex 请务必阅读viewabilityConfig

onViewableItemsChanged = ( viewableItems, changed ) => 
    if (viewableItems && viewableItems.length > 0) 
        this.setState( currentVisibleIndex: viewableItems[0].index );
    
;

如果有帮助请告诉我

【讨论】:

请您检查一下这个场景。 ***.com/questions/62468832/…【参考方案3】:

我终于用 redux 做到了。不知道这是否是正确的方式。

Home.js

_renderItem = (item, index) => <Posts item=item />

viewableItemsChanged = (props) => 
    let changed = props;
    let changedPostArray = []; 
    changed.map((v,i) => 
      let isViewable, item = v;
      if(!isViewable) 
        let post_id, type = item;
        if(type === 1)
          changedPostArray.push(post_id);
      
    );
    if(changedPostArray.length != 0)
      this.props.sendPostToPause(changedPostArray);
  

render() 
    return(
      <View style=flex: 1 >
          <FlatList
            ref=(ref) => this.homeList = ref
            refreshing=this.state.refreshing
            onRefresh=async () => 
              await this.setState(refreshing: true, postsId: [0], radiusId: 0, followingId: 0);
              this.getPosts();
            
            onEndReached=async () => 
              if(!this.state.isEnd) 
                await this.setState(isPaginate: true)
                this.getPosts()
              
            
            onEndReachedThreshold=0.2
            removeClippedSubviews=true
            contentContainerStyle=paddingBottom: 80
            data=this.state.followersRes            
            renderItem=this._renderItem
            viewabilityConfig=this.viewabilityConfig
            onViewableItemsChanged=this.viewableItemsChanged
          />
        </View>
        <Footer callback=this.scrollToTopAndRefresh />
      </View>
    )

export default connect(null, sendPostToPause)(Home);

Posts.js

class Posts extends React.PureComponent 

constructor()
 super()
 this.state: 
  pause: false
 


componentDidUpdate(prevProps) 
    if(prevProps != this.props) 
      this.props.postIdArray.map((v) => 
        if(v === prevProps.item.post_id) 
          this.setState(pause: true)
        
      )
    
  

render()
 return(
  <Video
    pause=this.state.pause
    //Other props
  />
 )





const mapStateToProps = (state) => 
  const postId = state.reducers;
  return 
    postIdArray: postId
  


export default connect(mapStateToProps, sendPostToPause)(withNavigation(Posts));

每当viewableItemsChanged 被触发时,我都会将更改后的帖子 ID 添加到数组中,并使用帖子 ID 数组调用操作。 在 Posts 组件中,我正在检查帖子 ID 是否匹配,如果匹配,我将暂停状态设置为 true。

【讨论】:

以上是关于不在视野范围内时暂停平面列表中的视频的主要内容,如果未能解决你的问题,请参考以下文章

Unity获取摄像机在某个平面上的视野范围

如何实现html5 video标签 手机浏览器播放视频事件判定播放中的视频超出电手机的浏览范围后视频暂停播放

计算不在相机视野范围内的模型的方法

Android - Google maps V2 - 计算当前不在视野中的标记是屏幕的北、东、南还是西

在 FlatList 中获取渲染视频的参考

java总结之基础类型与常量池