Pause video when new video plays react-native-video play - react-native

I have several Video players on a page.. would like to play only one video at a time so when one is playing, any other that was playing before stops... The Idea I had is to identify the ID of the video that has been tapped on then let this be the only video that is allowed to play so whatever was playing before should be paused. I am not sure of how to do this...
const MediaItem =({result}) => {
const [currentVideoPlayingId, setCurrentVideoPlayingId] = useState(' ')
const oneVideoPlaying = ()=>{
setCurrentVideoPlayingId(result.id)
}
console.log('currentVideoPlaying Id:',currentVideoPlayingId)
return (
<View style={styles.Container}>
<Card style={styles.CardView}>
<View style={styles.VideoItem}>
<VideoPlayer
video= {{uri:result.video_url} }
videoWidth={1600}
videoHeight={900}
ignoreSilentSwitch={"ignore"}
style={styles.Vid}
onStart={oneVideoPlaying}
thumbnail={{uri:result.thumbnail_url}}
/>
</View>
<Card.Title title={result.title} subtitle={result.description} />
</Card>
</View>
);
}
const styles = StyleSheet.create ({
Container: {
flex: 1
},
CardView:{
marginLeft:10,
marginRight:10,
marginTop: 20,
borderRadius:25,
width:320,
height:300
},
VideoItem:{
},
Vid:{
borderTopLeftRadius:25,
borderTopRightRadius:25,
},
})
export default MediaItem;

Related

Start playing a video at a time offset using expo-av on web

My goal is to start playing a video at a selected time offset. I am using the video component from expo-av since I want it to run on both web and device. It seems pretty straight forward by using the positionMillis props. This works well when I test it on Android - both in an emulator and device. However when I test on the web it always starts playing at the beginning of the video (time 0) Tested in both Chrome and Edge browsers (latest versions) I am new to expo and react-native, so please let me know if I am doing something wrong on the web
This is my simplified code
import React from 'react';
import { StyleSheet, Dimensions, View } from 'react-native';
import { Video } from 'expo-av'
export default function App() {
const url = require('./assets/sample.mp4')
// Start at 3 minute mark
const initSeek = 180000
const window = Dimensions.get("window");
const videoHeight = Math.floor(window.width / 1.777)
console.log("Video height %d width %d", videoHeight, window.width)
return (
<View style={styles.container}>
<Video
useNativeControls
resizeMode={'cover'}
source = {url}
positionMillis = {initSeek}
shouldPlay = {true}
style={ {width: '100%', height:videoHeight}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'flex-start',
justifyContent: 'flex-start',
},
});
This answer provides a method that works in my case - adding a ref
const _handleVideoRef = (component,) => {
const playbackObject = component;
playbackObject.playFromPositionAsync(initSeek)
}
...
ref={(component) => _handleVideoRef(component, initSeek)}
The full updated code snippet now works on both web and android. I am still interested if someone can explain why the original did not work - I seem to have a gap in my understanding
export default function App() {
const url = require('./assets/sample.mp4')
// Start at 3 minute mark
const initSeek = 180000
const window = Dimensions.get("window");
const videoHeight = Math.floor(window.width / 1.777)
console.log("Video height %d width %d", videoHeight, window.width)
const _handleVideoRef = (component,) => {
const playbackObject = component;
playbackObject.playFromPositionAsync(initSeek)
}
return (
<View style={styles.container}>
<Video
useNativeControls
ref={(component) => _handleVideoRef(component, initSeek)}
resizeMode={'cover'}
source = {url}
positionMillis = {initSeek}
shouldPlay = {true}
style={ {width: '100%', height:videoHeight}}
/>
</View>
);
}

How to play a video with react native video and pause other in flatlist

I am making a video app like tiktok / instagram reel and i have a flatlist as below
All my videos play automatically and i have it set so that its paused on render (at the moment), I am tying to play a video when it is visible on the screen and pause the other vodeos, but it doesn't work i can't seem to see anything online on how i can pause the other videos or possibly just render one video until i scroll but all videos are set to true no matter what i do.
how can i get the video that is visible to play and then pause when user scrolls and then play the other visible video?
I have been at this for 2 days and my head is Fried, any help would be appreciated :(
PostScreen.js
const [state, setState] = useState({
isVisible: false,
})
const videoData [
{
id: 1,
video: videourl
},
{
id: 2,
video: videourl
},
];
const _onViewableItemsChanged = useCallback(({ viewableItems }) => {
if(viewableItems[0]){
if(viewableItems[0].isViewable){
setState({...state, isVisible: true})
}
}
}, []);
const _viewabilityConfig = {
itemVisiblePercentThreshold: 50
}
<FlatList
data={videosData}
decelerationRate={'fast'}
showsVerticalScrollIndicator={false}
snapToInterval={Dimensions.get('window').height}
snapToAlignment={"start"}
initialScrollIndex={0}
disableIntervalMomentum
onViewableItemsChanged={_onViewableItemsChanged}
viewabilityConfig={_viewabilityConfig}
renderItem={ ({ item }) => (
<View>
<VideoPlayerComponent data={item} />
</View>
)}
/>
VideoPlayerComponent
const [data] = useState(props.data)
const [paused, setPaused] = useState(true);
return(
<View>
<TouchableWithoutFeedback
onPress={() => setPaused(!paused)}
>
<View>
<Video
style={styles.fullScreen}
source={data.video}
resizeMode="cover"
paused={paused}
repeat
/>
{
paused ? (
<View style={styles.pausedIcon}>
<Icon name="play" type="ionicon" color="white" size={68} />
</View>
): null
}
</View>
</TouchableWithoutFeedback>
</View>
)
friends I have solved the issue for my react native video project.
the issue was that all videos are playing in Flatlist but we need to play only singal video on the current viewport and pause the rest.
just do the following steps to solve all videos playing issue
1: npm install #svanboxel/visibility-sensor-react-native
2: import VisibilitySensor from '#svanboxel/visibility-sensor-react-native'
3: do this
import VisibilitySensor from '#svanboxel/visibility-sensor-react-native'
const video = ()=>{
const [paused, setpaused] = useState(true)
return(
<VisibilitySensor onChange={(isVisible)=>{
return(
console.log(isVisible),
isVisible?setpaused(false):setpaused(true)
)
}
}
>
<View>
<Video
source={{uri: 'https://d8vywknz0hvjw.cloudfront.net/fitenium-media-prod/videos/45fee890-a74f-11ea-8725-311975ea9616/proccessed_720.mp4'}}
style={styles.video}
onError={(e) => console.log(e)}
resizeMode={'cover'}
repeat={true}
paused={paused}
/>
</View>
</VisibilitySensor>
)
}
4: I have just given you the basic structure you can add styling stuff as your requirements.
5: remember that always add your view/video elements between the VisibilitySensor tags, otherwise it will not work.
6: this code will give you true when your video component will render in flatlist viewport and remainig will give you false. with this you can manage play/pause state of video element.
thanks...
I managed to use the inviewport library
using this snippiti managed to convert to functional class
in my functional class i just passed a flatlist as it was.
<FlatList
data={videos}
decelerationRate={'fast'}
showsVerticalScrollIndicator={false}
snapToInterval={Dimensions.get('window').height}
snapToAlignment={"start"}
initialScrollIndex={0}
disableIntervalMomentum
renderItem={ ({ item }) => (
<View>
<VideoPlayerComponent data={item}/>
</View>
)}
/>
then in my VideoPlayerComponent i do this
const video = useRef(ref)
const playVideo = () => {
if(video) {
setPaused(false);
}
}
const pauseVideo = () => {
if(video) {
setPaused(true);
}
}
const handlePlaying = (isVisible) => {
isVisible ? playVideo() : pauseVideo();
}
return (
<View>
<Video
ref={ ref => {video.current = ref}}
style={styles.fullScreen}
source={data.video}
paused={paused}
resizeMode="cover"
repeat
/>
</View>
)
This will play the video that is in. view and will pause the other based on the ref passed to it.
Hope this helps anyone stuck as i was stuck for a few days :)

Autoplay video on element focus in react-native

import {Video} from 'expo-av';
return (
<FlatList
data={videos}
// keyExtractor={(item,ind}
keyExtractor={(item) => item.names}
renderItem={({item})=>(
<TouchableOpacity
onPress={() => {console.log('pushed');navigation.push('Details',{url:item.videourl})}}>
<Video
usePoster="true"
source={{ uri: item.videourl }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="cover"
shouldPlay={isFocused ? true : false}
// isLooping
// useNativeControls
posterSource={{uri:item.imageurl}}
style={{ height: 300 }}
/>
</TouchableOpacity>
)}/>
);
If one video gets focused then the video must be played and if the video is not focused then it should pause.I am using expo-av for playing video. The above code is playing all videos on the screen but I want to play the video which is focused just like what youtube does.
To do this you need to keep track of how the scrollview has moved (the offset). FlatList has an onScroll property, where the callback is given information about the list layout etc., and you are interested in tracking how much the content has been scrolled vertically - that is contentOffset.y.
Dividing this value by the list item height (a constant 300 in your case) and rounding will give you the index of the item that should be playing.
Use state to store the currently focused index:
const [focusedIndex, setFocusedIndex] = React.useState(0);
Add a handler for the onScroll event :
const handleScroll = React.useCallback(({ nativeEvent: { contentOffset: { y } } }: NativeSyntheticEvent<NativeScrollEvent>) => {
const offset = Math.round(y / ITEM_HEIGHT);
setFocusedIndex(offset)
}, [setFocusedIndex]);
Pass the handler to your list:
<FlatList
onScroll={handleScroll}
...
/>
and modify the video's shouldPlay prop:
<Video
shouldPlay={focusedIndex === index}
...
/>
You can see a working snack here: https://snack.expo.io/#mlisik/video-autoplay-in-a-list, but note that the onScroll doesn't seem to be called if you view the web version.
Try https://github.com/SvanBoxel/visibility-sensor-react-native
Saved my time. You can use it like.
import VisibilitySensor from '#svanboxel/visibility-sensor-react-native'
const Example = props => {
const handleImageVisibility = visible = {
// handle visibility change
}
render() {
return (
<View style={styles.container}>
<VisibilitySensor onChange={handleImageVisibility}>
<Image
style={styles.image}
source={require("../assets/placeholder.png")}
/>
</VisibilitySensor>
</View>
)
}
}

How do I pause a playing video (played with react-native-video) when user scrolls to another page in a viewpager (#react-native-community/viewpager)?

In my app I am using a ViewPager (#react-native-community/viewpager) to display several pages. Some of these pages contain videos that I am displaying using react-native-video. If I start a video on one page and then scroll to the next page the video keeps playing in the background. The user can hear the audio of the video although the audio is not visible.
I would like to pause the video when the user scrolls to the next page, how do I accomplish that?
You can store the current page value in state and set some indexes to your pages, like in example below. After that just check if your page is current page:
<ViewPager
initialPage={0}
onPageScroll={({ nativeEvent }) => {
this.setState({
activePage: nativeEvent.position
})
}
}>
<View key="1">
<Video source={{ uri: '' }}
paused={this.state.activePage !== 0} />
</View>
<View key="2">
<Video source={{ uri: '' }}
paused={this.state.activePage !== 1} />
</View>
</ViewPager>
EDIT:
If you do not need the video to auto-start, you can add isPlaying property in state, and set it to true when you need.
<ViewPager
initialPage={0}
onPageScroll={({ nativeEvent }) => {
this.setState({
activePage: nativeEvent.position,
isPlaying: false
})
}
}>
<View key="1">
<Video source={{ uri: '' }}
paused={!this.state.isPlaying || this.state.activePage !== 0} />
</View>
<View key="2">
<Video source={{ uri: '' }}
paused={!this.state.isPlaying || this.state.activePage !== 1} />
</View>
</ViewPager>
You can check index of ViewPage with index of VideoItem when you map data.
Example:
<ViewPager
onPageSelected={this.onPageSelected}
initialPage={currentVisibleIndex}
style={{ width: '100%', height: '100%', justifyContent: 'center' }}
key={data.length}
// onPageScroll={this.onPageScroll}
scrollEnabled={data && data.length > 1}
// onPageScrollStateChanged={this.onPageScrollStateChanged}
>
{data.map((item, i) => {
if (isVideo(item)) {
return (
<VideoItem
uri={item}
key={i.toString()}
currentVisibleIndex={currentVisibleIndex}
currentIndex={i}
/>
);
}
return (
<ImageItem
uri={item}
defaultSource={Images.defaultImageAlbum}
key={i.toString()}
/>
);
})}
</ViewPager>
And in VideoItem.js you can use this to paused video when you scroll viewpager.
static getDerivedStateFromProps(props, state) {
let { paused } = state;
if (props.currentVisibleIndex !== props.currentIndex) {
paused = true;
}
return {
paused,
currentVisibleIndex: props.currentVisibleIndex
};
}
Sorry about my English.

Expo Video re-render on state change

I have a video where all I want it a play button over the top. I have achieved this with the following:
<View style={{ backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center'}}>
<Video
ref={setupVideo}
source={require('../../assets/AppSampleCoverVideo.mp4')} // TODO:
rate={1.0}
volume={1.0}
isMuted={false}
shouldPlay={isPlaying}
resizeMode='contain'
isLooping={false}
style={styles.setupVideo}
//onPlaybackStatusUpdate={onPlaybackStatusUpdate}
//useNativeControls={true}
/>
<TouchableOpacity style={styles.playButton} onPress={toggleVideoPlay}>
{
!isPlaying ? (
<Ionicons style={styles.playIcon} color='white' size={ Dimensions.get('window').width / 5 } name='ios-play' />
) : null
}
</TouchableOpacity>
</View>
I control the video with the following:
const [isPlaying, setIsPlaying] = useState(false)
const setupVideo = useRef(null);
const toggleVideoPlay = async () => {
try {
let videoStatus = await setupVideo.current.getStatusAsync();
if(videoStatus.isPlaying) {
return setupVideo.current.pauseAsync();
} else {
if(videoStatus.durationMillis === videoStatus.positionMillis) return setupVideo.current.replayAsync();
return setupVideo.current.playAsync();
}
} catch(err) {
}
}
However, I want to be able to track when the video is playing and when it is not in order to set the isPlaying and control whether the play button icon is rendered or not. Anything I have tried causes either the video to flicker when calling setIsPlaying or the video re-renders and doesn't play at all.
Any help would be appreciated.