flutter实现视频轮播

只要逻辑行得通,代码实现只是迟早的问题。产品经理想要视频轮播的功能,经过分析轮播的逻辑是很简单,只要当一个视频播放完成之后自动播放下一个视频,然后周而复始。前后也花了好几天的时间去尝试,皇天不负有心人,终于有所突破,在此记录一下,给需要的读者参考。

其中需要解决的问题如下:

1、如何获取播放完成的事件

2、在播放完成的事件触发之后如何更改视频源

代码中做注释会解答上面的1、2问题,其实在做的过程中还会遇到其它的棘手问题,尤其是状态改变之后会触发多次build,目前是通过标记位的方式来解决的,现在只是实现了两个视频轮播。

具体代码如下
 

import 'dart:async';
import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'package:video_player/video_player.dart';

///视频加载组件
class VideoLoader extends StatefulWidget {
  @override
  _VideoLoader createState() {
    return _VideoLoader();
  }
}

class _VideoLoader extends State<VideoLoader> {
  late VideoPlayerController _controller;

  //视频源列表,读者在使用代码时需要将视频源换成你自己的视频源
  List<String> _listVideoUrls = [
    "http://192.168.30.34/ims/resource/17d87da3-4021-48b8-9c68-0d53d0c349df.mp4",
    "http://192.168.30.34/ims/resource/17d87da3-4021-48b8-9c68.mp4"
  ];
  //定义两个标记位用来保证setstate()中的函数只执行一次.
  List<bool> flags = [false, false];


  @override
  void initState() {
    super.initState();
    playVideo1();
     
  }
//播放视频源1
  void playVideo1() async {
    _controller = VideoPlayerController.network(_listVideoUrls.elementAt(0));
    print('视频1加载完成');
    _controller.addListener(() async {
      Duration? res = await _controller.position;
      setState(() {
        if (res! >= _controller.value.duration) {


          if (!flags.elementAt(0)) {
            flags[0] = true;
            print('视频1播放完成');
            //移除当前_controller的监听事件
            _controller.removeListener(() {});
            _controller.dispose();
            if (flags[1] == true) {
              flags[1] = false;
              print('初始化flags[1] 为false');
            }

            playVideo2();
          }
        }
      });
    });
    _controller.setLooping(false);
    _controller.initialize().then((_) => setState(() {}));
    _controller.play();
  }

  

  void playVideo2() async {

    _controller = VideoPlayerController.network(_listVideoUrls.elementAt(1));
    print('视频2资源设置完成');
    _controller.addListener(() async {
      Duration? res = await _controller.position;
      setState(() {
        if (res! >= _controller.value.duration) {
          // print('_controller.value.duration:${_controller.value.duration}');

          if (!flags.elementAt(1)) {
            flags[1] = true;
            _controller.removeListener(() {});
            _controller.dispose();
            print('视频2播放完成');

            if (flags[0] == true) {
              flags[0] = false;
              print('初始化flags[0] 为false');
            }
            playVideo1();
          }
        }
      });
    });
    _controller.setLooping(false);
    _controller.initialize().then((_) => setState(() {}));

    _controller.play();
  }


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

  @override
  Widget build(BuildContext context) {
    print('build---------------');

    return Scaffold(
      // appBar: CupertinoNavigationBar(
      //   backgroundColor: Colors.white,
      //   middle: const Text('视频播放'),
      // ),

      body: Center(
          child: Container(
        // padding: const EdgeInsets.all(10.0),
        alignment: Alignment.center,

        child: GestureDetector(
          onTap: () {},
          child: Stack(
            alignment: Alignment.bottomCenter,
            children: <Widget>[
              VideoPlayer(_controller),
              //播放倍速
              _ControlsOverlay(controller: _controller),
              //播放进度条
              VideoProgressIndicator(_controller, allowScrubbing: true),
            ],
          ),
        ),
      )),
    );

  }
}

class _ControlsOverlay extends StatelessWidget {
  const _ControlsOverlay({Key? key, required this.controller})
      : super(key: key);

  static const _examplePlaybackRates = [
    0.25,
    0.5,
    1.0,
    1.5,
    2.0,
    3.0,
    5.0,
    10.0,
  ];

  final VideoPlayerController controller;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        AnimatedSwitcher(
          duration: Duration(milliseconds: 50),
          reverseDuration: Duration(milliseconds: 200),
          child: controller.value.isPlaying
              ? SizedBox.shrink()
              : Container(
                  color: Colors.black26,
                  child: Center(
                    child: Icon(
                      Icons.play_arrow,
                      color: Colors.white,
                      size: 100.0,
                    ),
                  ),
                ),
        ),
        GestureDetector(
          onTap: () {
            controller.value.isPlaying ? controller.pause() : controller.play();
          },
        ),
        Align(
          alignment: Alignment.topRight,
          child: PopupMenuButton<double>(
            initialValue: controller.value.playbackSpeed,
            tooltip: 'Playback speed',
            onSelected: (speed) {
              controller.setPlaybackSpeed(speed);
            },
            itemBuilder: (context) {
              return [
                for (final speed in _examplePlaybackRates)
                  PopupMenuItem(
                    value: speed,
                    child: Text('${speed}x'),
                  )
              ];
            },
            child: Padding(
              padding: const EdgeInsets.symmetric(
                // Using less vertical padding as the text is also longer
                // horizontally, so it feels like it would need more spacing
                // horizontally (matching the aspect ratio of the video).
                vertical: 12,
                horizontal: 16,
              ),
              child: Text('${controller.value.playbackSpeed}x'),
            ),
          ),
        ),
      ],
    );
  }
}

注意,如果项目中没有添加video_player包的话需要先在pubspec.yaml中添加。

 添加方式

在项目中执行 flutter pub add video_player

 添加完成之后 执行 flutter pub get命令。

添加好的pubspec.yaml结构如下:

依赖好之后就可以在项目中使用VideoPlayer相关资源了。

祝君成功,如有疑问可联系笔者交流!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

無昂博奥

测试下大赏功能,请勿大赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值