Working with Video Features
1. Configuring Video Source
| Property | Description | Values | Notes |
|---|---|---|---|
| source | Specifies the video source | uri, asset, file |
Required for video playback |
| uri | URL or file path to the video | string |
Supports local and remote video sources |
| asset | Asset reference to a video file | Asset |
Used for bundled assets in Expo |
| file | File path to the video on device | string |
Must be a valid file path on the device |
Example: Setting Video Source from URI
import { Video } from 'expo-av';
const VideoPlayer = () => {
return (
<Video
source={{ uri: 'https://example.com/video.mp4' }}
useNativeControls
style={{ width: '100%', height: 300 }}
/>
);
};
Example: Setting Video Source from Asset
import { Video } from 'expo-av';
import { Asset } from 'expo-asset';
const VideoPlayer = () => {
const videoAsset = Asset.fromModule(require('./assets/video.mp4'));
return (
<Video
source={{ asset: videoAsset }}
useNativeControls
style={{ width: '100%', height: 300 }}
/>
);
};
2. Setting Poster Image
| Property | Description | Default | Notes |
|---|---|---|---|
| poster | URL or local asset path for the video poster image | null |
Used when video is not playing or loading |
| posterResizeMode | How to resize the poster image | "cover" |
Options: "contain", "cover", "fill", "none", "repeat" |
Example: Setting a Poster Image
import { Video } from 'expo-av';
<Video
source={{ uri: 'https://example.com/video.mp4' }}
poster={require('./assets/poster.jpg')}
posterResizeMode="cover"
style={{ width: 300, height: 200 }}
/>
Note: The poster image is displayed while the video is loading or paused. It should be a static image that represents the content of the video.
3. Using Resize Modes
| Mode | Description | Usage |
|---|---|---|
| cover | Cover the entire area, maintaining aspect ratio. May crop. | resizeMode: 'cover' |
| contain | Fit the entire video within the area, maintaining aspect ratio. May leave empty space. | resizeMode: 'contain' |
| stretch | Stretch the video to fill the entire area. May distort aspect ratio. | resizeMode: 'stretch' |
| repeat | Repeat the video to fill the area. Not supported on all platforms. | resizeMode: 'repeat' |
| center | Center the video within the area, maintaining aspect ratio. | resizeMode: 'center' |
Example: Setting Resize Mode
import { Video } from 'expo-av';
<Video
source={{ uri: 'https://example.com/video.mp4' }}
resizeMode="cover"
style={{ width: 300, height: 200 }}
/>
4. Implementing Fullscreen Mode
Example: Toggle fullscreen mode
import { Video } from 'expo-av';
import { TouchableOpacity, Text } from 'react-native';
const VideoPlayer = () => {
const [isFullscreen, setIsFullscreen] = useState(false);
const toggleFullscreen = () => {
setIsFullscreen(!isFullscreen);
};
return (
<Video
source={{ uri: 'https://example.com/video.mp4' }}
style={{
width: isFullscreen ? '100%' : 300,
height: isFullscreen ? '100%' : 200,
}}
resizeMode={isFullscreen ? 'contain' : 'cover'}
controls={true}
/>
);
};
| Property | Description | Values |
|---|---|---|
| fullscreen | Enables or disables fullscreen mode | true | false |
| resizeMode | How the video should be resized to fit its container | 'contain' | 'cover' | 'stretch' |
Note: Fullscreen mode requires handling device orientation changes and layout adjustments for optimal user experience.
Warning: On some devices, entering fullscreen mode might cause the app to lose focus or trigger system UI changes.
5. Handling Video Events
| Event | Description | Properties |
|---|---|---|
| onLoad | Fired when the video is loaded and ready to play | duration, width, height |
| onProgress | Fired periodically as the video plays | currentTime, seekable |
| onEnd | Fired when the video finishes playing | didComplete |
| onError | Fired when an error occurs during video playback | error |
| onPlay | Fired when the video starts playing | isPlaying |
| onPause | Fired when the video is paused | isPlaying |
Example: Handling Video Events
import { Video } from 'expo-av';
const handleVideoEvent = (event) => {
if (event.type === 'onLoad') {
console.log('Video loaded:', event.data.duration);
} else if (event.type === 'onProgress') {
console.log('Current time:', event.data.currentTime);
} else if (event.type === 'onEnd') {
console.log('Video ended');
}
};
<Video
source={{ uri: 'https://example.com/video.mp4' }}
onLoad={handleVideoEvent}
onProgress={handleVideoEvent}
onEnd={handleVideoEvent}
onError={handleVideoEvent}
/>
6. Using Picture-in-Picture
| Property | Description | Notes |
|---|---|---|
| pictureInPicture | Enables or disables Picture-in-Picture mode for a video element. | Available on iOS and Android (requires Expo AV) |
Example: Enabling Picture-in-Picture
import { Video } from 'expo-av';\n\nconst MyVideoPlayer = () => {\n const videoRef = useRef(null);\n\n const togglePictureInPicture = async () => {\n if (videoRef.current) {\n await videoRef.current.setPictureInPicture(true);\n }\n };\n\n return (\n <Video\n ref={videoRef}\n source={{ uri: 'https://example.com/video.mp4' }}\n style={{ width: '100%', height: 300 }}\n pictureInPicture={true}\n /\>\n );\n};
Note: Picture-in-Picture is only supported on iOS 14+ and Android 8.0+.
7. Setting Playback Rate
| Property | Values | Description |
|---|---|---|
| rate | 0.25, 0.5, 1.0, 1.5, 2.0 |
Playback speed multiplier. 1.0 is normal speed. |
Example: Setting Playback Rate
import { Video } from 'expo-av';
<Video
source={{ uri: 'https://example.com/video.mp4' }}
rate={1.5}
style={{ width: 300, height: 200 }}
/>
Note: The
rate property affects how fast the video plays, but does not change audio pitch.
8. Implementing Video Controls
| Property | Description | Values |
|---|---|---|
| controls | Enables or disables video controls | true / false |
| paused | Pauses or resumes the video playback | true / false |
| muted | Mutes or unmutes the video audio | true / false |
| volume | Sets the volume level (0.0 to 1.0) | 0.0 - 1.0 |
| rate | Adjusts playback speed (1.0 = normal) | 0.0 - 2.0 |
Example: Basic Video Controls
import { Video } from 'expo-av';
<Video
source={{ uri: 'https://example.com/video.mp4' }}
controls={true}
paused={false}
muted={false}
volume={1.0}
rate={1.0}
style={{ width: '100%', height: 300 }}
/>
Example: Custom Video Controls
import { Video, Audio } from 'expo-av';
import { useState } from 'react';
const VideoPlayer = () => {
const [isPaused, setIsPaused] = useState(false);
const [isMuted, setIsMuted] = useState(false);
const [volume, setVolume] = useState(1.0);
return (
<Video
source={{ uri: 'https://example.com/video.mp4' }}
paused={isPaused}
muted={isMuted}
volume={volume}
style={{ width: '100%', height: 300 }}
/>
);
};
Note: The
controls prop enables default system controls, which may not be customizable. For fully custom controls, you must implement them separately using buttons and state management.
9. Seeking to Position
| Property | Description | Values | Notes |
|---|---|---|---|
| position | The position to seek to in seconds | number |
Must be a positive number or zero |
| seek | Method to seek to a specific position | function(position: number): void |
Triggers video playback to jump to the specified position |
Example: Seeking to a Position
import { Video } from 'expo-av';
const videoRef = useRef(null);
const seekToPosition = () => {
if (videoRef.current) {
videoRef.current.seek(30); // Seeks to 30 seconds
}
};
// In JSX:
<Video
ref={videoRef}
source={{ uri: 'https://example.com/video.mp4' }}
useNativeControls
onPlaybackStatusUpdate={status => {
if (status.positionMillis >= 30000) {
// Optional: Handle position reached
}
}}
/>
Note: The
seek method works only if the video is loaded and ready to play.
10. Handling Buffering State
| Property | Description | Values |
|---|---|---|
| buffering | Indicates if the video is currently buffering | true or false |
| buffered | Information about the buffered time ranges | Array<{ start: number, end: number }> |
| loading | Indicates if the video is loading | true or false |
Example: Handling Buffering State
import React, { useState } from 'react';
import { Video } from 'expo-av';
const VideoPlayer = () => {
const [isBuffering, setIsBuffering] = useState(false);
const [bufferedTime, setBufferedTime] = useState([]);
const onBuffer = (info) => {
setIsBuffering(info.isBuffering);
setBufferedTime(info.buffered);
};
return (
<Video
source={{ uri: 'https://example.com/video.mp4' }}
onBuffer={onBuffer}
useNativeControls
/>
);
};
export default VideoPlayer;
Note: The
onBuffer event provides real-time updates on buffering state, useful for UI feedback.