Building a Flutter Video Player App with Multiple Videos and Full-Screen Mode

Mohammed shamseer pv
4 min readNov 21, 2024

--

In this post, we will walk through creating a simple Flutter app that utilizes the video_player package to load and play multiple videos, along with supporting features like full-screen mode, volume control, and a custom UI for navigating between videos.

What We’ll Build

The app will have the following features:

  1. A video player to play videos from a list of URLs.
  2. The ability to switch between videos by tapping on a video thumbnail.
  3. Full-screen mode support, which will display the video in landscape orientation.
  4. Play/Pause functionality and volume control.
  5. A sleek UI with a video list and controls.

Let’s dive into the code!

Step 1: Setting Up Dependencies

To start, we need to add the video_player package to your pubspec.yaml file:

dependencies:
flutter:
sdk: flutter
video_player: ^2.5.0 # Check for the latest version

After adding this dependency, run flutter pub get to install the package.

Step 2: Creating the Video Player App

Here’s the main code for the app:

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:flutter/services.dart';

void main() => runApp(const VideoApp());

class VideoApp extends StatefulWidget {
const VideoApp({super.key});

@override
_VideoAppState createState() => _VideoAppState();
}

class _VideoAppState extends State<VideoApp> {
late VideoPlayerController _controller;
List<String> videoUrls = [
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/VolkswagenGTIReview.mp4',
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
];

double _volume = 1.0; // Volume level
bool _isFullScreen = false; // Full screen state

@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(videoUrls[0])
..initialize().then((_) {
_controller.play();
setState(() {});
});
}

void changeVideo(int index) {
setState(() {
_controller.pause(); // Pause the current video
_controller = VideoPlayerController.network(videoUrls[index])
..initialize().then((_) {
_controller.play();
setState(() {});
});
});
}

void toggleFullScreen(BuildContext context) {
setState(() {
_isFullScreen = !_isFullScreen;
});
if (_isFullScreen) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeRight]);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => FullScreenVideoPlayer(controller: _controller),
));
} else {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
Navigator.of(context).pop();
}
}

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Video Demo',
home: Scaffold(
appBar: AppBar(
title: const Text('Video Player Demo'),
),
body: Column(
children: [
Center(
child: _controller.value.isInitialized
? Stack(children: [
AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
),
Positioned.fill(
child: GestureDetector(
onTap: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Container(
color: Colors.black54,
child: Center(
child: Icon(
_controller.value.isPlaying
? Icons.pause
: Icons.play_arrow,
color: Colors.white,
size: 64.0,
),
),
),
),
),
Positioned(
bottom: 10,
left: 10,
right: 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(
_controller.value.isPlaying
? Icons.pause
: Icons.play_arrow,
color: Colors.white,
),
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
),
IconButton(
icon: Icon(
Icons.volume_up,
color: Colors.white,
),
onPressed: () {
setState(() {
_volume = _volume == 1.0 ? 0.0 : 1.0;
_controller.setVolume(_volume);
});
},
),
IconButton(
icon: Icon(
_isFullScreen
? Icons.fullscreen_exit
: Icons.fullscreen,
color: Colors.white,
),
onPressed: () {
toggleFullScreen(context);
},
),
],
),
),
])
: const CircularProgressIndicator(),
),
VideoProgressIndicator(_controller, allowScrubbing: true),
Expanded(
child: ListView.builder(
itemCount: videoUrls.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
changeVideo(index);
},
child: Container(
decoration: BoxDecoration(
color: Colors.white, // White color for the container
boxShadow: [
BoxShadow(
color: Colors.black
.withOpacity(0.1), // Light shadow color
offset: Offset(4.0, 4.0), // Shadow offset
blurRadius: 8.0, // Blur effect
spreadRadius: 2.0, // Spread the shadow a bit
),
],
borderRadius: BorderRadius.circular(12),
),
height: 150,
width: double.infinity,
child: Row(
children: [
SizedBox(width: 15),
Container(
height: 90,
width: 90,
child: Center(
child: Text("${index + 1}"),
),
decoration: BoxDecoration(
color: Color.fromARGB(255, 227, 225, 225),
borderRadius: BorderRadius.circular(12)),
),
],
),
),
),
);
},
),
),
],
),
),
);
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}
}

class FullScreenVideoPlayer extends StatelessWidget {
final VideoPlayerController controller;

const FullScreenVideoPlayer({Key? key, required this.controller})
: super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Center(
child: AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: VideoPlayer(controller),
),
),
Positioned.fill(
child: GestureDetector(
onTap: () {
controller.value.isPlaying
? controller.pause()
: controller.play();
},
child: Container(
color: Colors.black54,
child: Center(
child: Icon(
controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
size: 64.0,
),
),
),
),
),
Positioned(
bottom: 10,
left: 10,
right: 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
icon: Icon(
controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
),
onPressed: () {
controller.value.isPlaying
? controller.pause()
: controller.play();
},
),
IconButton(
icon: Icon(
Icons.volume_up,
color: Colors.white,
),
onPressed: () {
// Toggle volume logic can be added here
},
),
IconButton(
icon: Icon(
Icons.fullscreen_exit,
color: Colors.white,
),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
),
],
),
);
}
}

Step 3: Key Features Explained

  1. Multiple Video URLs: We store a list of video URLs and use VideoPlayerController to load the videos. The user can tap on a video thumbnail to switch to another video.
  2. Full-Screen Mode: We toggle full-screen mode using the SystemChrome.setEnabledSystemUIMode() method, which hides system UI elements like the status bar and navigation bar when the video is in full-screen.
  3. Play/Pause & Volume Control: The app allows users to play/pause videos by tapping on the screen, and toggle volume between 0 and 1 using a volume button.
  4. Responsive UI: The UI is designed to handle both portrait and landscape orientations, ensuring a smooth transition to full-screen mode.

Conclusion

This Flutter app is a great starting point to implement a video player with multiple video sources. With features like video switching, full-screen mode, and volume control, it provides an engaging and interactive experience. You can further customize this app by adding additional features like subtitles or background playback to enhance functionality.

Let me know if you have any questions or if you’d like to see more advanced features!

--

--

Mohammed shamseer pv
Mohammed shamseer pv

Written by Mohammed shamseer pv

skilled in Flutter, Node.js, Python, and Arduino, passionate about AI and creating innovative solutions. Active in tech community projects.

No responses yet