不在视图中时暂停 flatlist 中的视频
Pause video in flatlist when out of view
我有一个显示视频的平面列表。我希望当视频离开视图时应该暂停。我在每个 Posts
组件中保持暂停状态。
class Posts extends React.PureComponent {
constructor() {
super()
this.state = {
pause: true,
}
return(){
<Video
pause={this.state.pause}
//other props
/>
}
}
我正在使用 react-native-video
。
我试过使用 Flatlist
的 onViewableItemsChanged
道具,但它不会改变状态。
我试过了this。
但它似乎对我不起作用。
我应该如何进行?
我终于用 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
时,我都会在数组中添加更改后的 posts id,并使用 post id 的数组调用操作。
在 Posts
组件中,我正在检查 post id 是否匹配,如果匹配,我将暂停状态设置为 true。
这是使用 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
组件中。当它包围的组件 完全 在视口中时回调 returns 为真,当它没有完全在视口中时为假。回调调用 this.handlePlaying
,后者又根据布尔值调用 this.playVideo
或 this.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
组件。
这就是我如何做到这一点的
在我的卡片组件中有 video
<Video ...
paused={currentIndex !== currentVisibleIndex}
/>
currentIndex 和 currentVisibleIndex 都从 FlatList parent
传递给组件
我的 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 });
}
};
如果有帮助请告诉我
我有一个显示视频的平面列表。我希望当视频离开视图时应该暂停。我在每个 Posts
组件中保持暂停状态。
class Posts extends React.PureComponent {
constructor() {
super()
this.state = {
pause: true,
}
return(){
<Video
pause={this.state.pause}
//other props
/>
}
}
我正在使用 react-native-video
。
我试过使用 Flatlist
的 onViewableItemsChanged
道具,但它不会改变状态。
我试过了this。 但它似乎对我不起作用。
我应该如何进行?
我终于用 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
时,我都会在数组中添加更改后的 posts id,并使用 post id 的数组调用操作。
在 Posts
组件中,我正在检查 post id 是否匹配,如果匹配,我将暂停状态设置为 true。
这是使用 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
组件中。当它包围的组件 完全 在视口中时回调 returns 为真,当它没有完全在视口中时为假。回调调用 this.handlePlaying
,后者又根据布尔值调用 this.playVideo
或 this.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
组件。
这就是我如何做到这一点的 在我的卡片组件中有 video
<Video ...
paused={currentIndex !== currentVisibleIndex}
/>
currentIndex 和 currentVisibleIndex 都从 FlatList parent
传递给组件我的 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 });
}
};
如果有帮助请告诉我