You’ve seen many applications with video content, such as a recipe application with video tutorials, a movie application, and sports-related applications. Would you like to know how to add video content to your next Flutter application?

Implementing video functionality from scratch would be an onerous task. But there are several plug-ins that can make life easier for developers. The video player plugin is one of the best plug-ins available for Flutter to meet this requirement.

In this article, you will learn how to apply the video player plug-in and control the different features of the video player. We will discuss these topics.

  • Create a new video player
  • Add play and pause buttons
  • Create a fast forward
  • Add a video progress indicator
  • Apply subtitles to the video

Create a new video player

Before using the video player plug-in, you should add it to your Pubspec.yaml file. When you open the pubspec.yaml file, you can see some of the configurations and dependencies needed to run your application. Our video player plug-in should be added under the Dependencies block.

< span style = "font-size: 14px; line-height: 20pxCopy the code

The current version of the plug-in is 2.1.15, but you can add the latest version here by looking at the Plug-in page. If you save the file in VS Code, it will automatically download the plug-in. If not, open the terminal and write flutter pub get to download the plugin.

Go to the file where you want to add the plug-in and import the video_Player.dart file.

import 'package:video_player/video_player.dart';

Copy the code

Now you can use the video player plug-in in your project.

There are several ways to load video. Let’s load our example from the asset. Create an Assets/Video folder at the root of your project and add a video to that folder. Then in pubspec.yaml, in the Assets section, specify the file path as shown below.

assets:
    - assets/video/video.mp4

Copy the code

Let’s create a separate stateful widget, called the VideoPlayerWidget, to plug in our video player-related implementation.

You can initialize the video player in the initState method, as shown below. Also, don’t forget Dispose, let the video player do the cleaning.

class _VideoPlayerState extends State<VideoPlayerWidget> {
  late VideoPlayerController _videoPlayerController;
  @override
  void initState() {
    super.initState();
    _videoPlayerController = VideoPlayerController.asset(
        'assets/video/video.mp4')
      ..initialize().then((_) {
        setState(() {});
        _videoPlayerController.play();
      });
  }

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: VideoPlayer(_videoPlayerController),
    );
  }
}

Copy the code

The VideoPlayerController must be specified with the late keyword because we still haven’t defined the VideoPlayerController in this line, which we’ll do later. In initState, the videoPlayerController has been initialized along with the asset’s path.

When the initialization is complete, it changes the state and rebuilds the widget. You can start playing the video after initialization.

Instead of assets, you can use the URL of the video. To access the web, you should add Internet permissions to Android and iOS.

From the root directory, go to ios/Runner and open the info.plist file. Then, add the following configuration to the file.

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

Copy the code

Next, go to Android /app/ SRC /main and open androidmanifest.xml. Then, add the following code to it.

<uses-permission android:name="android.permission.INTERNET"/>

Copy the code

Now you can change asset to Network and add the video URL there.

@override void initState() { super.initState(); _videoPlayerController = VideoPlayerController.network('video_url_here') .. initialize().then((_) { setState(() {}); _videoPlayerController.play(); }); }Copy the code

Even after initialization is complete, there should be a way to display the player in the user interface. The VideoPlayer Widget can be used to do just that. To make it work, you should pass the controller as the first parameter to the VideoPlayer Widget.

Before displaying the VideoPlayer Widget, it is a good idea to check that the initialization was successful.

  @override
  Widget build(BuildContext context) {
    return Center(
      child: _videoPlayerController.value.isInitialized ? VideoPlayer(_videoPlayerController) : Container(),
    );
  }
Copy the code

Now you can see the video on the screen. But there’s one small problem: it doesn’t have the right aspect ratio. This can be solved by using AspectRatio Widget. The video player provides an appropriate AspectRatio for the video, and you can use this value to set it as an AspectRatio widget.

  @override
  Widget build(BuildContext context) {
    return Center(
      child: _videoPlayerController.value.isInitialized ? AspectRatio(aspectRatio: 
      _videoPlayerController.value.aspectRatio,
      child: VideoPlayer(_videoPlayerController)
      ) : Container(),
    );
  }

Copy the code

Now you can see the video with the appropriate aspect ratio.

Add play and pause buttons

First, let’s wrap the video player widget in a column widget, because we should put the play and pause buttons under the player. In the column after the player widget, let’s add two ElevatedButton widgets within a Row widget, and a Padding widget between the buttons to keep some breathing room.

For each ElevatedButton, add related Icons as child widgets. Then in the play button onPressed callback, you refer to _videoPlayerController and call the Play method to start playing the video. Inside the pause button, use pause instead of play.

Now you can remove the playback you added earlier in the initState method.

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        _videoPlayerController.value.isInitialized ? AspectRatio(aspectRatio: 
        _videoPlayerController.value.aspectRatio,
        child: VideoPlayer(_videoPlayerController)
        ) : Container(),
        Row(
          mainAxisAlignment: MainAxisAlignment.center, 
          children: [

            ElevatedButton(onPressed: (){
              _videoPlayerController.pause();
            }, child: Icon(Icons.pause)),
              Padding(padding: EdgeInsets.all(2)),
             ElevatedButton(onPressed: (){
              _videoPlayerController.play();
            }, child: Icon(Icons.play_arrow))
          ],
        )
      ],
    );
  }

Copy the code

In addition, you can style the button to get a round-looking button, usually in a video player.

 @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        _videoPlayerController.value.isInitialized
            ? AspectRatio(
                aspectRatio: _videoPlayerController.value.aspectRatio,
                child: VideoPlayer(_videoPlayerController))
            : Container(),
        Padding(
          padding: EdgeInsets.all(20),
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all<Color>(Colors.blue),
                    fixedSize: MaterialStateProperty.all(Size(70, 70)),
                    shape: MaterialStateProperty.all(RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(100)))),
                onPressed: () {
                  _videoPlayerController.pause();
                },
                child: Icon(Icons.pause)),
            Padding(padding: EdgeInsets.all(2)),
            ElevatedButton(
                style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all<Color>(Colors.redAccent),
                    fixedSize: MaterialStateProperty.all<Size>(Size(80, 80)),
                    shape: MaterialStateProperty.all(RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(100)))),
                onPressed: () {
                  _videoPlayerController.play();
                },
                child: Icon(Icons.play_arrow))
          ],
        )
      ],
    );
  }

Copy the code

Create a fast forward

Before implementing fast forward, let’s think about what we need. First, there should be a method to access the current video location/time and a method to set the new value. The controller’s seekTo method allows us to set the duration of the video.

You can access the current video location via the video player Value property, as shown below.

ElevatedButton(
       style: ButtonStyle(
          backgroundColor: MaterialStateProperty.all<Color>(Colors.blue),
          fixedSize: MaterialStateProperty.all(Size(70, 70)),
          shape: MaterialStateProperty.all(RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(100)))),
                onPressed: () {
                  _videoPlayerController.seekTo(Duration(
                   seconds: _videoPlayerController.value.position.inSeconds + 10));
                },
                child: Icon(Icons.fast_forward))
Copy the code

Like this, when the user clicks the button, you can also reverse it by cutting 10 seconds off.

Add a video progress indicator

The video player plugin provides built-in functionality to add a progress bar as well as controls. You can do this using the VideoProgressIndicator Widget.

As the first argument, you must pass the controller and set the allowScrubbing property. The allowScrubbing property will allow the user to slide progress by touching the widget. By enabling this, the user can jump to different timestamps of the video. Additionally, you can individually control the background color, buffer color, and play area color of the search bar.

VideoProgressIndicator(
          _videoPlayerController,
          allowScrubbing: true,
          colors: VideoProgressColors(
              backgroundColor: Colors.red,
              bufferedColor: Colors.black,
              playedColor: Colors.blueAccent),
        )

Copy the code

Apply subtitles to the video

Subtitles need two things for your application. The first is a list of paragraphs/words from different periods, and the second is a way to display these titles while the video is playing. To do this, there should be a way to add a listener for time changes.

The video player contains an addListener method that executes every second. You can use this listener to provide subtitles for your video player for different time periods.

First, let’s create a Map that contains the time as a key and the subtitle text as a value. In Map, time will be in seconds.

Map<int,String> captions = {
    5:"First subtitle",
    20:"Second subtitle"
  };

Copy the code

Next, register a Listener when initializing the video player. In the callback, you can check if the video is playing, and if the video is playing, get the current time in seconds. Then, if the current value is included in the Captions map, we can set that value to the selected title as follows.

void initState() { super.initState(); _videoPlayerController = VideoPlayerController.asset('assets/video/video.mp4') .. addListener(() { if(_videoPlayerController.value.isPlaying){ setState(() { if(captions.containsKey(_videoPlayerController.value.position.inSeconds)){ selectedCaption = captions[_videoPlayerController.value.position.inSeconds]; }}); }}).. initialize().then((_) { setState(() {}); _videoPlayerController.play(); }); }Copy the code

Now you can use ClosedCaption to set that selected title. You can add styles to the header text for better visibility.

 ClosedCaption(
     text: selectedCaption,textStyle: TextStyle(fontSize: 15,color: Colors.white),)

Copy the code

However, it is not good practice to build the main widget every time the title changes. Therefore, we should extract the heading logic into a separate widget.

To register a listener, you should pass the video controller to a newly created child widget. From there, you can register listeners within child widgets.

class VCaption extends StatefulWidget { const VCaption( this.videoPlayerController, ); final VideoPlayerController videoPlayerController; @override _VCaptionState createState() => _VCaptionState(); } class _VCaptionState extends State<VCaption> { String? selectedCaption = ""; Map<int,String> captions = { 5:"First subtitle", 20:"Second subtitle" }; @override void initState() { widget.videoPlayerController.addListener(() { if(widget.videoPlayerController.value.isPlaying){ print("Time ${widget.videoPlayerController.value.position.inSeconds}"); setState(() { if(captions.containsKey(widget.videoPlayerController.value.position.inSeconds)){ selectedCaption = captions[widget.videoPlayerController.value.position.inSeconds]; }}); }}); super.initState(); } @override Widget build(BuildContext context) { return ClosedCaption( text: selectedCaption,textStyle: TextStyle(fontSize: 15,color: Colors.white),); }}Copy the code

Now we can add the widget to the column we created earlier and pass _videoPlayerController as a parameter. You can check to see if the video player is initialized before adding the widget to the tree, as shown below.

 _videoPlayerController.value.isInitialized ? VCaption(_videoPlayerController) : Container(),

Copy the code

You can use the Stack Widget to display these captions at the top of the video, rather than at the bottom. Subtitles and progress indicators have been moved into the Stack widget to be displayed at the top of the video.

 Stack(
          children: [
            _videoPlayerController.value.isInitialized
                ? AspectRatio(
                    aspectRatio: _videoPlayerController.value.aspectRatio,
                    child: VideoPlayer(_videoPlayerController))
                : Container(),
            Positioned(
              bottom: 2,
              width: MediaQuery.of(context).size.width,
              child: _videoPlayerController.value.isInitialized
                  ? VCaption(_videoPlayerController)
                  : Container(),
            ),
            Positioned(
                bottom: 0,
                width: MediaQuery.of(context).size.width,
                child: VideoProgressIndicator(
                  _videoPlayerController,
                  allowScrubbing: false,
                  colors: VideoProgressColors(
                      backgroundColor: Colors.blueGrey,
                      bufferedColor: Colors.blueGrey,
                      playedColor: Colors.blueAccent),
                ))
          ],
        )

Copy the code

conclusion

Using a video player plug-in instead of implementing a video player from scratch saves a lot of development time and provides all the functionality right out of the box.

If you want to go beyond these customizations and implement a beautiful video player inspired by Material- and Cupertino, you can choose the Chewie Flutter plugin.

The postHandling videos in Flutter using a video player pluginappeared first onLogRocket Blog.