File video player widget

A widget created to play videos from files in flutter. The width and height of the widget is controlled by the parent. This is used mostly for preview videos that just got captured from the camera or where selected from the gallery.

Dependencies

Add the following packages in the pubspec.yaml first.

  1. video_player: ^version

and run the pub get command from the terminal.

Usage

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _recordingState == RecordingState.preview
            ? PreviewWidget(videoFile, onPreviewDone)
            : RecordWidget(widget.question, fileCallback, onExit),
      ),
    );
  }

onPreviewDone(path, index) async {
    if (path == null) {
      ScaffoldMessenger.of(context)
          .showSnackBar(SnackBar(content: Text('Couldn\'t get video')));
    } else {
      setState(() {
        // upload to backend. Navigate away
      });
    }
  }

Parameters

@videoFile : Mandatory. The video file to be previewed @doneCallback : Mandatory. The callback to call when the user wants to navigate away from the screen

Widget

class PreviewWidget extends StatefulWidget {
  PreviewWidget(this.videoFile, this.doneCallback, {Key key, scaffoldKey})
      : super(key: key);

  final XFile videoFile;
  final Function(bool) doneCallback;

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

class _PreviewWidgetState extends State<PreviewWidget>
    with WidgetsBindingObserver {
  VideoPlayerController videoController;
  VoidCallback videoPlayerListener;

  @override
  void initState() {
    _startVideoPlayer();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Stack(
          children: [
            _buildRecordingPreview(context),
            Padding(
              padding: const EdgeInsets.all(Dimens.paddingBig),
              child: Align(
                  alignment: Alignment.bottomRight,
                  child: Padding(
                    padding: const EdgeInsets.all(Dimens.padding),
                    child: Align(
                      alignment: Alignment.bottomCenter,
                      child: IconButton(
                        icon: Icon(Icons.navigate_next),
                        iconSize: 80,
                        color: Colors.blue,
                        onPressed: () {
                          widget.doneCallback(true);
                        },
                      ),
                    ),
                  )),
            )
          ],
        ),
      ),
    );
  }

  _buildRecordingPreview(BuildContext context) {
    return Container(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.height,
        child: Center(
          child: videoController != null
              ? VideoPlayer(videoController)
              : Container(child: Text(Strings.loading)),
        ));
  }

  Future<void> _startVideoPlayer() async {
    final VideoPlayerController vController =
        VideoPlayerController.file(File(widget.videoFile.path));
    videoPlayerListener = () {
      if (videoController != null && videoController.value.size != null) {
        // Refreshing the state to update video player with the correct ratio.
        if (mounted) setState(() {});
        videoController.removeListener(videoPlayerListener);
      }
    };
    vController.addListener(videoPlayerListener);
    await vController.setLooping(true);
    await vController.initialize();
    final VideoPlayerController oldController = videoController;
    if (mounted) {
      setState(() {
        videoController = vController;
      });
    }
    await vController.play();
    await oldController?.dispose();
  }
}