This document provides an overview of a custom video player widget built using Chewie and video_player packages. This custom video player is designed to be used within a FlutterFlow project.
Introduction
Having worked through a number of examples shared within the community, I found that, over time, these examples have become unusable, either because they were incomplete, or that packages and solutions become superseded.
My requirement was quite simple. I wanted the ability to display a full-screen video with audio in portrait mode, which autoplays when the page is loaded, taking the file from Firebase storage. I also wanted the ability to pause and restart the image when tapping on the screen. After a bit of playing around with the scarce documentation online, I finally got the solution working, which I am happy to share with the wider FF community.
Overview
This custom video player widget uses chewie
, a wrapper around video_player
, to provide a more user-friendly video player interface. The widget allows playing videos from network URLs, with features such as play/pause on tap, volume control, and aspect ratio adjustments.
Dependencies
Make sure you have the following dependencies in Flutterflow:
chewie: 1.7.5
video_player: (Use the one in Flutterflow)
Code
// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
// Define a custom widget named CustomVidPlayer
class CustomVidPlayer extends StatefulWidget {
CustomVidPlayer({
this.width,
this.height,
required this.videoPath,
});
final double? width;
final double? height;
final String videoPath;
@override
_CustomVidPlayerState createState() => _CustomVidPlayerState();
}
class _CustomVidPlayerState extends State<CustomVidPlayer> {
late VideoPlayerController _videoPlayerController;
late ChewieController _chewieController;
late Future<void> _initializeVideoPlayerFuture;
double videoContainerRatio = 0.5;
@override
void initState() {
super.initState();
_videoPlayerController =
VideoPlayerController.networkUrl(Uri.parse(widget.videoPath));
_initializeVideoPlayerFuture = _videoPlayerController.initialize();
_videoPlayerController.setVolume(1.0);
}
@override
void dispose() {
_videoPlayerController.dispose();
_chewieController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
aspectRatio: _videoPlayerController.value.aspectRatio,
autoInitialize: true,
looping: false,
showControls: false,
autoPlay: true,
);
return Container(
child: Transform.scale(
scale: getScale(),
child: AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: Stack(
children: [
// Display the video using Chewie
Chewie(
controller: _chewieController,
),
GestureDetector(
onTap: toggleVideoPlayback, // play / pause video on tap
behavior: HitTestBehavior.opaque,
),
],
),
),
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
double getScale() {
double videoRatio = _videoPlayerController.value.aspectRatio;
if (videoRatio < videoContainerRatio) {
///for tall videos, we just return the inverse of the controller aspect ratio
return videoContainerRatio / videoRatio;
} else {
///for wide videos, divide the video AR by the fixed container AR
///so that the video does not over scale
return videoRatio / videoContainerRatio;
}
}
void toggleVideoPlayback() {
if (_videoPlayerController.value.isPlaying) {
_chewieController.pause();
print("Paused");
} else {
_chewieController.play();
print("Playing");
}
}
}
Parameters
What’s Going On?
Imports and Initialization:
The required packages and dependencies are imported.
VideoPlayerController
fromvideo_player
package andChewieController
fromchewie
package are used.
CustomVidPlayer Widget:
This widget takes
width
,height
, andvideoPath
as parameters.width
andheight
define the size of the video player.videoPath
is the URL of the video to be played.
State Management:
_CustomVidPlayerState
manages the state of the video player.The
initState
method initializes the video player with the provided video URL and sets the volume.
Video Player Initialization:
_initializeVideoPlayerFuture
is used to handle the asynchronous initialization of the video player.
Dispose Method:
The
dispose
method disposes of the video player controller and chewie controller to free up resources.
Build Method:
The
build
method uses aFutureBuilder
to ensure the video is loaded before displaying it.A
ChewieController
is created to manage the video player settings such as aspect ratio, auto play, and looping.The
Container
widget usesTransform.scale
to maintain the aspect ratio and scale of the video.
Helper Methods:
getScale
method adjusts the scale of the video based on its aspect ratio.toggleVideoPlayback
method toggles the video playback between play and pause on tap.
Notes
The
Chewie
package provides a simplified wrap around the video_player interface with custom controls.Ensure to use compatible versions of
chewie
andvideo_player
to avoid conflicts with other dependencies, such as provider.
This documentation should help developers understand and use the custom video player widget in their FlutterFlow projects.
Happy Coding.
Article originally published here: Flutterflow Custom Video Player. Video Player Widget (Chewie) | by Rocco Labellarte | May, 2024 | Medium