I'm trying to do this in react native using av-expo.
When the button is pressed, a video component is rendered in fullscreen mode, portrait orientation.
When exiting from fullscreen, the video component is hidden.
I'm not able to:
show it in fullscreen mode
detect the exiting event from the fullscreen mode.
function showVideo(){
<Video
source={{ uri:'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4' }}
resizeMode="cover"
useNativeControls
style={{ width: 300, height: 300 }}/>
}
export default function App(){
const[state,setState]=useState(0)
return(
<View>
{state ? showVideo() : null}
<Button onPress={=>(setState(1)}/>
<View>
)
}
Would anyone please help me?
Since you use av-expo; there are FullScreen APIs for you.
The following methods are available on the component's ref:
videoRef.presentFullscreenPlayer(); use this to present Video in the fullscreen mode.
videoRef.dismissFullscreenPlayer()
and use onPlaybackStatusUpdate, a function to be called regularly with the onFullscreenUpdate, a function to be called when the state of the native iOS fullscreen view changes (controlled via the presentFullscreenPlayer() and dismissFullscreenPlayer() methods on the Video's ref.
export default class App extends React. Component{
_videoRef;
showVideoInFullscreen = async () => {
// PlaybackStatus https://docs.expo.io/versions/latest/sdk/av/
const status = await this._videoRef.presentFullscreenPlayer();
console.log(status)
}
dismissVideoFromFullscreen = async () => {
const status = await this._videoRef.dismissFullscreenPlayer();
console.log(status);
}
onFullscreenUpdate = ({fullscreenUpdate, status}) => {
console.log(fullscreenUpdate, status)
switch (fullscreenUpdate) {
case Video.FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT:
console.log(' the fullscreen player is about to present');
break;
case Video.FULLSCREEN_UPDATE_PLAYER_DID_PRESENT:
console.log('the fullscreen player just finished presenting');
break;
case Video.FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS:
console.log('the fullscreen player is about to dismiss');
break;
case Video.FULLSCREEN_UPDATE_PLAYER_DID_DISMISS:
console.log('the fullscreen player just finished dismissing');
}
}
render () {
return (
<View style={styles.container}>
<Video
ref={(ref) => (this._videoRef = ref)}
source={{ uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4' }}
resizeMode="cover"
useNativeControls
onFullscreenUpdate={this.onFullscreenUpdate}
style={{ width: 300, height: 300 }}
/>
<Button
title={'show video'}
onPress={() => {
this.showVideoInFullscreen();
}}
/>
</View>
);
}
}
output
the fullscreen player is about to present
the fullscreen player just finished presenting
the fullscreen player is about to dismiss
the fullscreen player just finished dismissing
Related
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>
)
}
}
I wanted to ask what would be the best way to handle loading for videos on Expo / React Native.
Expo has good documentation on the Video and AV components to handle video / audio:
https://docs.expo.io/versions/latest/sdk/video/
https://docs.expo.io/versions/latest/sdk/av/
I've tried two things so far: '
Using posterSource in a Video component. The problem here is that the poster image doesn't format properly.
This is what my Video component looks like:
const videoStyle = { width: '100%', height: '100%', display: display};
return (
<Video
ref={playbackObject}
source={{uri: source}}
posterSource={require('path/to/file')}
rate={1.0}
volume={1.0}
isMuted={isMuted}
resizeMode="cover"
usePoster={true}
shouldPlay={shouldPlay}
onPlaybackStatusUpdate={_onPlaybackStatusUpdate}
progressUpdateIntervalMillis={50}
isLooping
style={videoStyle}
posterStyle={videoStyle}
>
</Video>
)
I’ve also tried using playbackStatus to see if the video is loaded or buffering and have an activity indicator when the video is loaded or buffering, but because I use states, there is some lag.
My implementation for (2) looks like this:
const [loaded, setLoaded] = useState(false);
const _onPlaybackStatusUpdate = playbackStatus => {
if(playbackStatus.isBuffering){
if(loaded){
setLoaded(false);
}
} else {
if(!loaded){
setLoaded(true);
}
}
}
If loaded = true, we do not show an activity indicator. Else, we do show an activity indicator. The main problem here is there is a lag, which is not great UI.
So with that in mind, what would be people’s recommendation of handling loading for videos? Thanks!!
What you can do is to render an <ActivityIndicator /> as background and when it finishes loading the asset, it will get behind the video (or you could just check if the asset was loaded or not -> optionally rendering it inside <Video />.
<Video
ref={handleVideoRef}
>
<ActivityIndicator size="large" />
</Video>
const handleVideoRef = async component => {
const playbackObject = component;
if (playbackObject) {
await playbackObject.loadAsync(
{ uri: currentVideoURI },
);
}
};
here's my solution for that :
Video component has onLoadStart and onReadyForDisplay props, which indicate when the loading starts and when it's finished.
So we could create a custom component, which would support loading indicator using the Video component imported from expo. So in the end, this would looksomething like this :
import React, {useState} from "react";
import { ActivityIndicator } from "react-native";
import { Video } from "expo-av";
const AppVideo = ({style, ...rest}) => {
return (
<View style={style}>
{isPreloading &&
<ActivityIndicator
animating
color={"gray"}
size="large"
style={{ flex: 1, position:"absolute", top:"50%", left:"45%" }}
/>
}
<Video
{...rest}
onLoadStart={() => setIsPreloading(true)}
useNativeControls
onReadyForDisplay={() => setIsPreloading(false)}
resizeMode="contain"
isLooping
/>
</View>
);
}
export default AppVideo;
I'm trying to do this by react-native using the av-expo video.
What I'm trying to do is to launch the video directly in full screen without going through the "Video" stack (without the double loading of the MediaPlayerScreen stack + the native fullScreen stack).
If the user mutes the full screen by the native fullScreen output button, then we go back directly to a stack
The idea is to use only the native fullscreen stack to display the video. Is this possible?
I don't know if I'm clear, if it can help to understand, here is the code of my MediaPlayerScreen component
export class MediaPlayerScreen extends Component {
static navigationOptions = {
//header: null,
headerTitle: '',
headerTransparent: false,
headerTintColor: 'white',
}
constructor(props) {
super(props)
this.AG = AG.instance
this.filePath =
this.AG.getFilePath() + props.navigation.state.params.file
this.windowWidth = Dimensions.get('window').width
this.windowHeight = Dimensions.get('window').height
}
//
onPlaybackStatusUpdate = (playbackStatus) => {
if (playbackStatus.didJustFinish) {
this.props.navigation.goBack()
}
}
//
_handleVideoRef = async (component) => {
const playbackObject = component
if (playbackObject) {
await playbackObject.loadAsync({
uri: this.filePath,
shouldPlay: false,
posterSource: this.poster,
})
// todo: Trigger fullScreen without videoStack loading
//playbackObject.presentFullscreenPlayer();
playbackObject.playAsync()
//playbackObject.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate);
}
}
componentDidMount() {
ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE)
}
componentWillUnmount() {
//playbackObject.dismissFullscreenPlayer();
//this.props.navigation.goBack();
ScreenOrientation.lockAsync(
ScreenOrientation.OrientationLock.PORTRAIT_UP
)
}
onFullscreenUpdate = ({ fullscreenUpdate, status }) => {
console.log(fullscreenUpdate, status)
switch (fullscreenUpdate) {
case Video.FULLSCREEN_UPDATE_PLAYER_WILL_PRESENT:
console.log(' the fullscreen player is about to present')
break
case Video.FULLSCREEN_UPDATE_PLAYER_DID_PRESENT:
console.log('the fullscreen player just finished presenting')
break
case Video.FULLSCREEN_UPDATE_PLAYER_WILL_DISMISS:
console.log('the fullscreen player is about to dismiss')
break
case Video.FULLSCREEN_UPDATE_PLAYER_DID_DISMISS:
console.log('the fullscreen player just finished dismissing')
}
}
render() {
return (
<SafeAreaView style={styles.container}>
<Video
ref={this._handleVideoRef}
useNativeControls
rate={1.0}
resizeMode="contain"
onPlaybackStatusUpdate={(playbackStatus) =>
this.onPlaybackStatusUpdate(playbackStatus)
}
onFullscreenUpdate={this.onFullscreenUpdate}
style={{
width: this.windowHeight,
height: this.windowWidth,
}}
/>
</SafeAreaView>
)
}
}
Thanks for your help,
Meums/
hey if I am not getting you wrong you want to load the player fullscreen by default.you can follow this approach:
const videoRef = useRef(null);
<Video
ref={videoRef}
useNativeControls={false}
style={styles.container}
isLooping
source={{
uri: videoUri,
}}
onLoad={()=>{
videoRef?.current?.presentFullscreenPlayer();
}
resizeMode="contain"
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
/>
I am facing this weird issue, my youtube videos are not playing if the fullscreen is set to false. But if I set it to true, then it works fine. I dont need the full screen. Following is my code
{this.state.showYoutube &&
<YouTube
apiKey="MY-YOUTUBE-API-KEY"
videoId={this.state.videoId} // The YouTube video ID
play={false} // control playback of video with true/false
fullscreen={false} // control whether the video should play in fullscreen or inline
loop={false} // control whether the video should loop when ended
//onReady={e => this.setState({ isReady: true })}
//onChangeState={e => this.setState({ status: e.state })}
//onChangeQuality={e => this.setState({ quality: e.quality })}
//onError={e => this.setState({error: e.error})}
onError={e => console.log(e.error)}
style={{alignSelf: 'stretch', height: 300}}
/>
}
if this.state.showYoutube is set to true then Youtube will be shown and the this.state.videoId is set after an api call,
I have used height and removed native base drawer after facing overlaying issue. Then it was working.
But now it is not working again, please tell me what I am doing wrong.
Found the solution here
export default class extends Component {
state = {
height: 215
}
handleReady = () => {
setTimeout(() => this.setState({ height: 216 }), 500);
}
render() {
return (
<YouTube
apiKey = {config.YOUTUBE_API_KEY}
ref = {item => this.player = item}
videoId = {getVideoId(uri)}
controls = {1}
onReady = {this.handleReady}
style = {{ alignSelf: 'stretch', height: height }}
/>
);
}
}
It worked for me, but still there is a known issue which is that if resumed from a full screen, the screen is not auto oriented.
I want to play an audio file, But it's playing automaticaly and I can't pause That.
How Can I Fix That?
That Must be Paused at the begin
My Code:
import Video from 'react-native-video';
export default class Android extends Component {
constructor(props) {
super(props)
this.state = {
paused: true,
}
}
video: Video;
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
<Video
ref={(ref: Video) => { this.video = ref }}
source={{ uri: "http://s3.picofile.com/d/7376893331/8b7bc5b4-4b5e-47c4-96dd-b0c13fd18157/Sara_Diba_Delbare_Man.mp3", mainVer: 1, patchVer: 0 }}
paused={this.state.paused}
/>
</View>
);
}
}
There's currently a bug in react-native-video where the pause flag is ignored when the component is first loaded. You have to change pause AFTER the component has loaded.
First, make sure your this.state.pause = false. Then:
<Video
paused={this.state.paused}
onLoad={() => {
this.setState({
paused: true
});
}}
</Video>
Context: https://github.com/react-native-community/react-native-video/issues/494#issuecomment-281853423
Use ref attribute to create a link to the video and using that reference we can able to use video controls on the video component
Try this code,
import React from "react";
class VideoDemo extends React.Component {
getVideo = elem => {
this.video = elem
}
playVideo = () => {
// You can use the play method as normal on your video ref
this.video.play()
};
pauseVideo = () => {
// Pause as well
this.video.pause();
};
render = () => {
return (
<div>
<video
ref={this.getVideo}
src="http://techslides.com/demos/sample-videos/small.mp4"
type="video/mp4"
/>
<div>
<button onClick={this.playVideo}>
Play!
</button>
<button onClick={this.pauseVideo}>
Pause!
</button>
</div>
</div>
);
};
}
export default VideoDemo;