¿Cómo puedo detectar el progreso (inicializar/finalizar) del reproductor de video en Flutter?

3 minutos de lectura

Soy muy nuevo en Flutter y no sé mucho al respecto.

Estoy usando video_player y el paquete chewie en Flutter. Quiero enviar datos analíticos cuando el video comienza y finaliza.

Entonces, quiero saber ambos tiempos. ¿Cómo puedo detectar el tiempo de inicio/finalización del video?

Mi código es el siguiente.

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

class VideoItem extends StatefulWidget {
  final VideoPlayerController videoPlayerController;
  final bool looping;

  VideoItem({
    @required this.videoPlayerController,
    this.looping,
    Key key,
  }) : super(key: key);

  @override
  _VideoState createState() => _VideoState();

}

class _VideoState extends State<VideoItem> {
  ChewieController _chewieController;

  @override
  void initState() {
    super.initState();

    _chewieController = ChewieController(
      videoPlayerController: widget.videoPlayerController,
      aspectRatio: 1 / 1,
      autoPlay: true,
      autoInitialize: true,
      looping: widget.looping,
      allowFullScreen: false,
      allowMuting: true,
      errorBuilder: (context, errorMessage) {
        return Center(
          child: Text(
            errorMessage,
            style: TextStyle(color: Colors.white),
          ),
        );
      },
    );
  }

...

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(0.0),
      child: Chewie(
        controller: _chewieController,
      ),
    );
  }
}

Avatar de usuario de Mazin Ibrahim
Mazín Ibrahim

Agrega un Listener función a su videoPlayerController y dentro de esa función verifique la posición actual de su VideoPlayer :

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

class VideoItem extends StatefulWidget {
  final VideoPlayerController videoPlayerController;
  final bool looping;

  VideoItem({
    @required this.videoPlayerController,
    this.looping,
    Key key,
  }) : super(key: key);

  @override
  _VideoState createState() => _VideoState();

}

class _VideoState extends State<VideoItem> {
  ChewieController _chewieController;

  @override
  void initState() {
    super.initState();

    widget.videoPlayerController.addListener(checkVideo);

    _chewieController = ChewieController(
      videoPlayerController: widget.videoPlayerController,
      aspectRatio: 1 / 1,
      autoPlay: true,
      autoInitialize: true,
      looping: widget.looping,
      allowFullScreen: false,
      allowMuting: true,
      errorBuilder: (context, errorMessage) {
        return Center(
          child: Text(
            errorMessage,
            style: TextStyle(color: Colors.white),
          ),
        );
      },
    );
  }

...

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(0.0),
      child: Chewie(
        controller: _chewieController,
      ),
    );
  }

    void checkVideo(){
    // Implement your calls inside these conditions' bodies : 
    if(videoPlayerController.value.position == Duration(seconds: 0, minutes: 0, hours: 0)) {
      print('video Started');
    }

    if(videoPlayerController.value.position == videoPlayerController.value.duration) {
      print('video Ended');
    }

  }
} 

  • checkVideo() solo llama la primera vez.

    – Samar Alí Qazalbash

    18 de febrero de 2020 a las 6:39

  • ¿Cómo puedo detectar buscar cambios? ¿Hay algo que pueda anular o crear un oyente?

    – Dragisa Dragisic

    8 de abril de 2021 a las 11:49

avatar de usuario de raj kavadia
raj kavadia

Lo que puede hacer es inicializar el controlador de video_player y agregarle un oyente personalizado. Aquí está ese fragmento.

  _videoController = VideoPlayerController.file(File(s));

  _videoController.initialize().then((value) => {
        _videoController.addListener(() {                       //custom Listner
          setState(() {
            if (!_videoController.value.isPlaying &&_videoController.value.initialized &&
                (_videoController.value.duration ==_videoController.value.position)) { //checking the duration and position every time
              setState(() {});
            }
          });
        })
      });

Aquí no estoy seguro de cuántos segundos golpea, pero funciona bastante bien para mí.

Avatar de usuario de SalahAdDin
SalahAdDin

Podemos hacer lo mismo usando flutter_hooks:

@override
  Widget build(BuildContext context) {
    final VideoPlayerController _videoPlayerController =
        VideoPlayerController.network(dataSource);
    final ValueNotifier<bool> _isVideoFinished = useState(false);

    useEffect(() {
      void checkIsFinished() {
        _isVideoFinished.value = _videoPlayerController.value.isInitialized &&
            _videoPlayerController.value.position ==
                _videoPlayerController.value.duration;
      }

      _videoPlayerController.addListener(checkIsFinished);
      return () {
        _videoPlayerController.removeListener(checkIsFinished);
      };
    }, <VideoPlayerController>[_videoPlayerController]);

    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: IntroductionScreen(
        pages: <PageViewModel>[
          PageViewModel(
            title: "",
            image: VideoItem(
              videoPlayerController: _videoPlayerController,
              autoPlay: true,
            ),
            body: "",
            decoration: const PageDecoration(fullScreen: true),
          ),
        ],
        done: const Text("Done", style: TextStyle(fontWeight: FontWeight.w600)),
        showDoneButton: _isVideoFinished.value,
        onDone: onDone,
        showNextButton: false,
      ),
    );
  }

No olvides usarlo en un HookWidget.

¿Ha sido útil esta solución?