Change Videos Dynamically in Flutter using the video_player package
Flutter is a popular cross-platform framework for building high-performance
mobile applications. One of the exciting things about Flutter is that it
makes it easy to build rich, interactive apps with minimal effort. In this
tutorial, we will build a video player app using Flutter that allows you to
play videos from a list of URLs.
Setting up the project
Run the following command to create a new Flutter project:
flutter create videoplayer
Go inside the directory by running the command:
cd videoplayer
Import the
video_player package provided by the
flutter.dev team to play the videos. To
import the package, run the command:
flutter pub add video_player
Note: Remove every line of code that is not relevant to the project (i.e.,
comments, unused variables, or functions).
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: MyHomePage());
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return const Scaffold();
}
}
Declaring the variables
Create a new dart file called globals.dart, which will contain all the
global variables.
Define a list of Strings called videos that contains the video URLs to display.
List<String> videos = [
'https://download.samplelib.com/mp4/sample-5s.mp4',
'https://download.samplelib.com/mp4/sample-10s.mp4',
'https://download.samplelib.com/mp4/sample-15s.mp4',
'https://download.samplelib.com/mp4/sample-20s.mp4',
'https://download.samplelib.com/mp4/sample-30s.mp4',
];
We will
also define a VideoPlayerController object and a ValueNotifier object with a
type of nullable Future<VoidCallback>.
VideoPlayerController videoPlayerController = VideoPlayerController.network('');
ValueNotifier<Future<void>?> videoFuture = ValueNotifier(null);
The ValueNotifier videoFuture stores the play function's future. The ValueListenableBuilder widget listens to videoFuture changes and updates the video player when play is called.
Creating the play() function
Create a new dart file called functions.dart.
Create a function called play that takes a URL as an argument.
Future<void> play(String url) async {
if (url.isEmpty) return;
if (videoPlayerController.value.isInitialized) {
await videoPlayerController.dispose();
}
videoPlayerController = VideoPlayerController.network(url);
return videoPlayerController
.initialize()
.then((value) => videoPlayerController.play());
}
The function checks if the URL is empty. If it is, it returns immediately. If not, it disposes the current VideoPlayerController and creates a new one with the given URL. It then initializes and plays the video.
Creating the LoadingScreen and BlankScreen
This step is optional, but the application must tell the user what the current state of the video player is,
whether it is currently loading a video, or it does not have one at all.
Create another dart file called widgets.dart. Inside, define
two additional widgets: BlankScreen and LoadingScreen.
The BlankScreen
widget is displayed when no video is selected.
class BlankScreen extends StatelessWidget {
const BlankScreen({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.black,
alignment: Alignment.center,
child: const Text(
'Tap on any video to start watching.',
style: TextStyle(color: Colors.grey),
),
);
}
}
The LoadingScreen widget
is displayed while the selected video is being loaded.
class LoadingWidget extends StatelessWidget {
const LoadingWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Colors.black,
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox.square(
dimension: 15,
child: CircularProgressIndicator(),
),
SizedBox(width: 20),
Text(
'Loading...',
style: TextStyle(color: Colors.white),
)
],
),
);
}
}
Note: These are just stateless widgets and are purely used for visuals, so you can create your own widget or just copy the code.
Modifying the MyHomePage widget
Go to the main.dart file and inside the MyHomePage widget, create a Column widget wrapped inside a SafeArea widget at the body of the Scaffold.class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return const Scaffold(
body: SafeArea(
child: Column(
children: [
// Top - Video Player
// Bottom - ListView
],
),
),
);
}
}
Creating the video player
For the video player, we will use a ValueListenableBuilder widget to listen for changes in the ValueNotifier called videoFuture.// Top - Video Player
ValueListenableBuilder(
valueListenable: videoFuture,
builder: // ...,
)
Inside the ValueListenableBuilder, use an AspectRatio widget and set the aspect ratio property to 16 / 9.
// ValueListenableBuilder widget...
builder: (context, value, child) {
return AspectRatio(
aspectRatio: 16 / 9,
child: // ...
);
},
// ...
On the child of the AspectRatio widget, use a ternary operator to check if the videoNotifier has value or none. If the value is equal to null, simply return a BlankScreen.
// AspectRatio widget...
child: value == null
? const BlankScreen()
: // Do something when value is not null...
// ...
If the value is a future, we use FutureBuilder to build a widget that depends on the future's result (play() function). It automatically rebuilds the widget when the future completes. Set the future property to the ValueListenableBuilder value.
// AspectRatio widget...
child: value == null
? const BlankScreen()
: FutureBuilder(
future: value,
builder: // ...
),
// ...
// FutureBuilder widget...
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return VideoPlayer(videoPlayerController);
} else {
return const LoadingWidget();
}
},
// ...
Creating the ListView
Create a ListView.builder widget wrapped inside an Expanded Widget and set the itemCount property to the number of items in the videos list.
In the itemBuilder function, return a ListTile widget for each item in the list. Set the title and subtitle properties of the ListTile to display the video's title and URL using the index parameter to access the elements of the videos list.
To enable video selection and playback, set the ListTile's onTap property to a function that assigns the videoFuture's value to the play() function with the video URL.
// Bottom - ListView
Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: videos.length,
itemBuilder: // ...,
),
),
// ListView.builder widget...
itemBuilder: (context, index) => ListTile(title: Text('Video ${index + 1}'),
subtitle: Text(videos[index]),
onTap: () => // ...,
),
// ...
// ListView.builder widget...
onTap: () => videoFuture.value = play(videos[index]),
// ...
Comments
Post a Comment