This is a flutter package of video player. it's a very simple and easy to use.

Last update: May 22, 2022

awsome_video_player

pub package

一个简单易用的而且可高度自定义的播放器。

原型图

工欲善其事,必先利其器

闲话不多说我们直接上“干货”。

Q:播放器就播放器,为什么要强调上高度自由呢? A:之所以强调高度自由是因为播放器上面的能见的元素你都可以去更改,同时提供很多的回调可以进行自定义处理。主要还是体现在了自定义这个方面。(你可以拿它去仿 blibli ,腾讯播放器等等)

Q:高度自由体现在哪些功能或者配置上面? A:最能体现自由的是播放器的自定义拓展元素功能,但是往往很多集成的开发者都忽略了这一点,因为这个确实很方便,但是很多播放器都没能做到这一点;其次,利用自定义顶部控制拦可以添加很多 actions操作,通过自定义拓展元素这个功能来辅助实现;最后,自定义底部控制拦可以添加或减少控制元素,更改进度条的样式等等。

Q:播放器目前具备哪些能力? A:目前还在完善当中,但是功能基本都已经完善了,剩下的就是根据开发者的反馈去优化和完善了,下面是我罗列的功能列表:

  • 1.自定义图标(所有)
  • 2.播放器自定义配置
    • 视频开始播放的起始位置
    • 是否自动播放
    • 是否循环播放
    • 视频比例
    • 进度条是否允许拖拽
    • 视频快进/快退的单位秒数
  • 3.自定义拓展元素(无限)
    • 字幕(也可以使用内置字幕)
    • 弹幕
    • 其他元素(例如:广告覆盖;自定义视频顶部返回按钮;快进或快退等操作的渐入渐出的提示等等)
  • 4.自定义播放器样式
    • 播放按钮是否显示(视频暂停时视图中央的播放按钮)
    • 自定义播放按钮(视频暂停时视图中央的播放按钮)
    • 顶部控制栏自定义
      • 显示或隐藏
      • 自定义高度
      • 自定义边距
      • 自定义背景颜色
      • 自定义返回按钮
      • 拓展中部元素(标题)
      • 拓展右侧控制元素(更多操作)
    • 底部控制栏自定义配置
      • 自定义顺序(通过数组来控制元素:线形进度条、矩形进度条等)
      • 自定义元素(通过数组来控制顺序)
      • 自定义背景颜色
      • 自定义图标(播放、暂停、快进、快退、全屏、取消全屏)
      • 进度条样式自由配置(背景颜色、缓存区颜色、进度条颜色、拖拽按钮颜色、拖拽按钮颜色等)
      • 音量控制元素(尚未完成)
      • 内置弹幕(尚未完成,尚可自定义)
      • 控制栏拓展(尚未完成)
    • 内置字幕自定义配置(或者通过自定义拓展来自己重写字幕)
      • 设置主字幕或辅字幕的字体大小
      • 设置主字幕或辅字幕的字体颜色
  • 5.手势支持
    • 单击(菜单栏显示或隐藏)
    • 双击(暂停或播放)
    • 滑动快进或快退
    • 滑动调整视频亮度 (左侧区域)
    • 滑动调整音量大小(右侧区域)
  • 6.横竖屏切换
  • 7.常亮避免锁屏

一张效果图

一张效果图

前往快乐的源泉

播放器属性

逻辑思维图

通过上图我们可以看一下播放器都有哪些属性呢?

属性 类型 描述
dataSource String 视频URL或媒体文件的路径
playOptions VideoPlayOptions 视频播放自定义配置,包含是否自动播放,是否循环播放等(详情见下方的Useage
videoStyle VideoStyle 视频播放器自定义样式,自定义顶部控制拦样式、自定义底部控制拦样式、自定义Loading样式等(详情见下方的Useage
children List 自定义拓展的元素,需要使用 Widget Align(字幕、弹幕、广告、封面等其他自定义元素)
回调方法 类型 描述
oninit VideoCallback 初始化完成回调
onplay VideoCallback 视频开始播放的回调
onpause VideoCallback 视频暂停播放回调
ontimeupdate VideoCallback 视频播放进度回调(通过返回的value进行字幕匹配)
onend VideoCallback 视频播放结束回调
onvolume VideoCallback 播放声音大小变化回调
onbrightness VideoCallback 屏幕亮度变化回调
onpop VideoCallback 顶部控制栏返回按钮点击回调
onnetwork VideoCallback 网络变化回调
onfullscreen VideoCallback 视频是否全屏回调
onprogressdrag VideoProgressDragHandle 进度条被拖拽的回调

播放器自定义配置 (VideoPlayOptions)

属性 类型 描述
startPosition Duration 开始播放节点,例如:Duration(seconds: 0))
loop bool 是否循环播放
seekSeconds num 设置视频快进/快退单位秒数,默认为15s
progressGestureUnit num 设置(横向)手势调节视频进度的秒数单位,默认为1s
volumeGestureUnit num 设置(右侧垂直)手势调节视频音量的单位,必须为0~1之间(不能小于0,不能大于1),默认为0.01
brightnessGestureUnit num 设置(左侧垂直)手势调节视频亮度的单位,必须为0~1之间(不能小于0,不能大于1),默认为0.01
autoplay bool 是否自动播放
aspectRatio num 视频播放比例,例如:16/9 或者 4/3
allowScrubbing bool 是否允许进度条拖拽

播放器自定义样式 (VideoStyle)

属性 类型 描述
playIcon Widget 视频暂停播放时中央显示的图标,showPlayIcon为false时,该属性设置无效。
replayIcon Widget 视频结束时中央显示的重播图标,showReplayIcon为false时,该属性设置无效。
showPlayIcon bool 暂停时是否显示播放按钮
showReplayIcon bool 视频播放结束时是否显示重播按钮
videoTopBarStyle VideoTopBarStyle 视频顶部自定义样式(详情见下方的Useage
videoControlBarStyle VideoControlBarStyle 控制栏自定义样式(详情见下方的Useage
videoSubtitlesStyle VideoSubtitles 字幕自定义样式(详情见下方的Useage
videoLoadingStyle VideoLoadingStyle 视频缓冲或者初始化Loading的自定义样式(详情见下方的Useage

自定义顶部控制栏 (VideoTopBarStyle):

属性 类型 描述
show bool 是否显示控制栏
barBackgroundColor Color 控制栏背景颜色,默认为Color.fromRGBO(0, 0, 0, 0.5)
height double 自定义控制栏高度
padding EdgeInsets 自定义边距
popIcon Widget 自定义返回按钮
contents List 拓展控制栏中部元素(宽度自适应: Row中的 Expanded
actions List 拓展控制栏右侧控制元素
customBar Widget 重写控制栏(如果设置了customBar, 除show属性意外上方属性均不生效),仅支持AlignPositioned

自定义顶部控制栏

自定义底部控制栏样式 (VideoControlBarStyle):

属性 类型 描述
height double 控制栏高度,默认为30
padding EdgeInsets 控制栏内边距,默认为EdgeInsets.symmetric(vertical: 8, horizontal: 10)
progressStyle VideoProgressStyle 自定义控制拦进度条样式
barBackgroundColor Color 控制栏背景颜色,默认为Color.fromRGBO(0, 0, 0, 0.5)
timePadding EdgeInsets 视频时间的内边距,默认为EdgeInsets.symmetric(horizontal: 5)
timeFontSize double 视频时间的字体大小,默认为8
timeFontColor Color 视频时间的颜色,默认为Color.fromRGBO(255, 255, 255, 1)
playIcon Widget 控制栏播放图标(下图3详细说明)
pauseIcon Widget 控制栏暂停图标(下图3详细说明)
rewindIcon Widget 控制栏快退图标(下图3详细说明)
forwardIcon Widget 控制栏快进图标(下图3详细说明)
fullscreenIcon Widget 控制栏全屏图标(下图3详细说明)
fullscreenExitIcon Widget 控制栏取消全屏图标(下图3详细说明)
itemList List 控制栏自定义功能(下图4详细说明),默认为["rewind", "play", "forward", "position-time", "progress", "duration-time", "fullscreen"]。如果我们需要调整控制栏显示的顺序,仅需要调整 list 中字符串的顺序,如果需要删减,直接从 list 中移除改字符串即可,例如移除快进和快退,则讲 list 设置为 ["play", "progress","position-time", "progress", "duration-time", "fullscreen"] 即可。后面会陆续开放自定义元素,也就是你把你的元素加入到 list 中。
图3

图4

自定义进度条样式 (VideoProgressStyle) :

属性 类型 描述
padding EdgeInsets 进度条边距(itemList中包含progress有效)
height double 进度条高度(itemList中包含progress有效)
dragHeight double 进度条拖拽按钮高度(itemList中包含progress有效)
progressRadius double 进度条圆角(itemList中包含progress有效)
playedColor Color 已播放的进度条颜色(见下图)
bufferedColor Color 已缓冲的进度条颜色(见下图)
backgroundColor Color 进度条背景颜色(见下图)
dragBarColor Color 进度条拖拽按钮演示(itemList中包含progress有效)

更改颜色

自定义控制栏功能 (itemList) :

属性 类型 描述
rewind String 快退功能,对应VideoControlBarStylerewindIcon图标
play String 播放/暂停功能,对应VideoControlBarStyleplayIcon pauseIcon图标
forward String 快进功能,对应VideoControlBarStyleforwardIcon图标
progress String 线条形进度条(与‘basic-progress’二选一),由VideoControlBarStyleprogressStyle控制样式
basic-progress String 矩形进度条(与‘progress’二选一),由VideoControlBarStyleprogressStyle控制样式
time String 时间格式:当前时间/视频总时长(与position-timeduration-time二选一),由VideoControlBarStyletimePadding timeFontSize timeFontColor控制样式
position-time String 当前播放时间,样式控制与time相同
duration-time String 视频总时长,样式控制与time相同
fullscreen String 全屏/小屏功能,对应VideoControlBarStylefullscreenIcon fullscreenExitIcon图标

如何使用?

Install & Set up

  1. 添加依赖,打开根目录的pubspec.yaml文件,在dependencies:下面添加以下代码

    awsome_video_player: #latest
  2. 安装依赖(如果已经自动安装请忽略)

    cd 项目目录
    flutter packages get
  3. 在页面中引入库

    import 'package:awsome_video_player/awsome_video_player.dart';

Useage

这是一个完整的DEMO

main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  String mainSubtitles = "主字幕";
  String subSubtitles = "辅字幕";

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Awsome video player'),
        ),
        body: Center(
          child: AwsomeVideoPlayer(
            "https://www.runoob.com/try/demo_source/movie.mp4",
            /// 视频播放配置
            playOptions: VideoPlayOptions(
              seekSeconds: 30,
              aspectRatio: 16 / 9,
              loop: true,
              autoplay: true,
              allowScrubbing: true,
              startPosition: Duration(seconds: 0)),
            /// 自定义视频样式
            videoStyle: VideoStyle(
            	/// 自定义视频暂停时视频中部的播放按钮
              playIcon: Icon(
                Icons.play_circle_outline,
                size: 100,
                color: Colors.white,
              ),
              /// 暂停时是否显示视频中部播放按钮
              showPlayIcon: true,
              /// 自定义底部控制栏
              videoControlBarStyle: VideoControlBarStyle(
                /// 自定义颜色
                //barBackgroundColor: Colors.blue,
                /// 自定义进度条样式
                progressStyle: VideoProgressStyle(
                  // padding: EdgeInsets.all(0),
                  playedColor: Colors.red,
                  bufferedColor: Colors.yellow,
                  backgroundColor: Colors.green,
                  dragBarColor: Colors.white,//进度条为`progress`时有效,如果时`basic-progress`则无效
                  height: 4,
                  progressRadius: 2,//进度条为`progress`时有效,如果时`basic-progress`则无效
                  dragHeight: 5//进度条为`progress`时有效,如果时`basic-progress`则无效
                ),
                /// 更改进度栏的播放按钮
                playIcon: Icon(
                  Icons.play_arrow,
                  color: Colors.white,
                  size: 16
                ),
                /// 更改进度栏的暂停按钮
                pauseIcon: Icon(
                  Icons.pause,
                  color: Colors.red,
                  size: 16,
                ),
                /// 更改进度栏的快退按钮
                rewindIcon: Icon(
                  Icons.replay_30,
                  size: 16,
                  color: Colors.white,
                ),
                /// 更改进度栏的快进按钮
                forwardIcon: Icon(
                  Icons.forward_30,
                  size: 16,
                  color: Colors.white,
                ),
                /// 更改进度栏的全屏按钮
                fullscreenIcon: Icon(
                  Icons.fullscreen,
                  size: 16,
                  color: Colors.white,
                ),
                /// 更改进度栏的退出全屏按钮
                fullscreenExitIcon: Icon(
                  Icons.fullscreen_exit,
                  size: 16,
                  color: Colors.red,
                ),
                /// 决定控制栏的元素以及排序,示例见上方图3
                itemList: [
                  "rewind",
                  "play",
                  "forward",
                  "position-time", //当前播放时间
                  "progress",//线形进度条
                  //"basic-progress",//矩形进度条
                  "duration-time", //视频总时长
                  // "time", //格式:当前时间/视频总时长
                  "fullscreen"
                ],
              ),
              /// 自定义字幕
              videoSubtitlesStyle: VideoSubtitles(
              	mianTitle: Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    padding: EdgeInsets.fromLTRB(10, 0, 10, 30),
                    child: Text(
                    		mainSubtitles,
                        maxLines: 2,
                        textAlign: TextAlign.center,
                        style: TextStyle(
                            color: Colors.white, fontSize: 14)),
                  ),
                ),
                subTitle: Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    padding: EdgeInsets.all(10),
                    child: Text(
                    		subSubtitles,
                        maxLines: 2,
                        textAlign: TextAlign.center,
                        style: TextStyle(
                            color: Colors.white, fontSize: 14)),
                  ),
                ),
              ),
            ),
            /// 自定义拓展元素
            children: [
              /// 这个将会覆盖的视频内容,因为这个层级是最高级,因此手势会失效(慎用)
              /// 这个可以用来做视频广告
              // Positioned(
              //   top: 0,
              //   left: 0,
              //   bottom: 0,
              //   right: 0,
              //   child: Text("data", style: TextStyle(color: Colors.white),),
              // ),
            ],
            /// 视频初始化完成回调
            oninit: (controller) {
              print("video oninit");
            },
            /// 视频播放回调
            onplay: (value) {
              print("video played");
            },
            /// 视频暂停回调
            onpause: (value) {
              print("video paused");
            },
            /// 视频播放结束回调
            onended: (value) {
              print("video ended");
            },
            /// 视频播放进度回调
            /// 可以用来匹配字幕
            ontimeupdate: (value) {
              print("timeupdate $value");
              var position = value.position.inMilliseconds / 1000;
              //根据 position 来判断当前显示的字幕
            },
            /// 声音变化回调
            onvolume: (value) {
              print("onvolume $value");
            },
            /// 亮度变化回调
            onbrightness: (value) {
              print("onbrightness $value");
            },
            /// 网络变化回调
            onnetwork: (value) {
              print("onbrightness $value");
            },
            /// 顶部控制栏点击返回按钮
            onpop: (value) {
              print("返回上一页");
            },
          ),
        ),
      ),
    );
  }
}

DEMO示例

1. 自定义控制栏图标

首先我来看一下控制栏的图标自定义(见上图1):

DEMO: main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Awsome video player'),
        ),
        body: Center(
          child: AwsomeVideoPlayer(
            "https://www.runoob.com/try/demo_source/movie.mp4",
            /// 视频播放配置
            playOptions: VideoPlayOptions(
              seekSeconds: 30,
              aspectRatio: 16 / 9,
              loop: true,
              autoplay: true,
              allowScrubbing: true,
              startPosition: Duration(seconds: 0)),
            /// 自定义视频样式 - 请注意我要划重点了
            videoStyle: VideoStyle(
              /// 自定义底部控制栏  - 这是重点了
              videoControlBarStyle: VideoControlBarStyle(
                /// 更改进度栏的播放按钮
                playIcon: Icon(
                  Icons.play_arrow,
                  color: Colors.white,
                  size: 16
                ),
                /// 更改进度栏的暂停按钮
                pauseIcon: Icon(
                  Icons.pause,
                  color: Colors.red,
                  size: 16,
                ),
                /// 更改进度栏的快退按钮
                rewindIcon: Icon(
                  Icons.replay_30,
                  size: 16,
                  color: Colors.white,
                ),
                /// 更改进度栏的快进按钮
                forwardIcon: Icon(
                  Icons.forward_30,
                  size: 16,
                  color: Colors.white,
                ),
                /// 更改进度栏的全屏按钮
                fullscreenIcon: Icon(
                  Icons.fullscreen,
                  size: 16,
                  color: Colors.white,
                ),
                /// 更改进度栏的退出全屏按钮
                fullscreenExitIcon: Icon(
                  Icons.fullscreen_exit,
                  size: 16,
                  color: Colors.red,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

2. 自定义控制栏元素和顺序

我们可以根据videoStylevideoControlBarStyle来自定义控制栏的样式:调整顺序(见上方图3)只需要调整 itemList中字符串的顺序即可;控制显示的元素,将不需要暂时的元素从 itemList 中删除即可。

DEMO: main.dart

import 'package:flutter/material.dart';

import 'package:awsome_video_player/awsome_video_player.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Awsome video player'),
        ),
        body: Center(
          child: AwsomeVideoPlayer(
            "https://www.runoob.com/try/demo_source/movie.mp4",
            /// 视频播放配置
            playOptions: VideoPlayOptions(
              seekSeconds: 30,
              aspectRatio: 16 / 9,
              loop: true,
              autoplay: true,
              allowScrubbing: true,
              startPosition: Duration(seconds: 0)),
            /// 自定义视频样式 - 请注意我要划重点了
            videoStyle: VideoStyle(
              /// 自定义底部控制栏  - 这是重点了
              videoControlBarStyle: VideoControlBarStyle(
                /// 决定控制栏的元素以及排序,示例见上方图3
                itemList: [
                  "progress",// 这里将进度条前置了,因此有了图3的效果
                  "rewind",//如果需要删除快退按钮,将其注释或删除即可
                  "play",
                  "forward",
                  "time",
                  "fullscreen"
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

3. 自定义进度条以及控制栏的背景颜色

同样我们还是通过videoStylevideoControlBarStyle来自定义进度条的颜色(见上方图3)。

DEMO: main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Awsome video player'),
        ),
        body: Center(
          child: AwsomeVideoPlayer(
            "https://www.runoob.com/try/demo_source/movie.mp4",
            /// 视频播放配置
            playOptions: VideoPlayOptions(
              seekSeconds: 30,
              aspectRatio: 16 / 9,
              loop: true,
              autoplay: true,
              allowScrubbing: true,
              startPosition: Duration(seconds: 0)),
            /// 自定义视频样式
            videoStyle: VideoStyle(
              /// 自定义底部控制栏
              videoControlBarStyle: VideoControlBarStyle(
                /// 自定义颜色
                barBackgroundColor: Colors.blue,//控制栏的背景颜色

                /// 自定义进度条样式
                progressStyle: VideoProgressStyle(
                  // padding: EdgeInsets.all(0),
                  playedColor: Colors.red,
                  bufferedColor: Colors.yellow,
                  backgroundColor: Colors.green,
                  dragBarColor: Colors.white,//进度条为`progress`时有效,如果时`basic-progress`则无效
                  height: 4,
                  progressRadius: 2,//进度条为`progress`时有效,如果时`basic-progress`则无效
                  dragHeight: 5//进度条为`progress`时有效,如果时`basic-progress`则无效
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

4. 自定义顶部控制栏

通过videoStylevideoTopBarStyle来自定义顶部控制栏。

DEMO image

DEMO: main.dart

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String videoUrl = "https://www.runoob.com/try/demo_source/movie.mp4";
  bool showAdvertCover = false;//是否显示广告

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Awsome video player'),
        ),
        body: Center(
          child: videoUrl != ""
              ? AwsomeVideoPlayer(
                  videoUrl,

                  /// 视频播放配置
                  playOptions: VideoPlayOptions(
                      seekSeconds: 30,
                      aspectRatio: 16 / 9,
                      loop: true,
                      autoplay: true,
                      allowScrubbing: true,
                      startPosition: Duration(seconds: 0)),

                  /// 自定义视频样式
                  videoStyle: VideoStyle(

                    /// 自定义顶部控制栏
                    videoTopBarStyle: VideoTopBarStyle(
                      show: true, //是否显示
                      height: 30,
                      padding:
                          EdgeInsets.symmetric(vertical: 8, horizontal: 10),
                      barBackgroundColor: Color.fromRGBO(0, 0, 0, 0.5),
                      popIcon: Icon(
                        Icons.arrow_back,
                        size: 16,
                        color: Colors.white,
                      ),
                      contents: [
                        Center(
                          child: Container(
                            margin: EdgeInsets.symmetric(horizontal: 10),
                            child: Text(
                              '123',
                              style: TextStyle(color: Colors.white),
                            ),
                          ),
                        )
                      ], //自定义顶部控制栏中间显示区域
                      actions: [
                        GestureDetector(
                          onTap: () {
                            ///1. 可配合自定义拓展元素使用,例如广告
                            setState(() {
                              showAdvertCover = true;
                            });
                            ///
                          },
                          child: Icon(
                            Icons.more_horiz,
                            size: 16,
                            color: Colors.white,
                          ),
                        )
                      ], //自定义顶部控制栏右侧显示区域
                      /// 设置cusotmBar之后,以上属性均无效(除了`show`之外)
                      // customBar: Text("123123132")
                    ),
                  ),

                  /// 顶部控制栏点击返回按钮
                  onpop: (value) {
                    print("返回上一页");
                  },
                )
              : AspectRatio(
                  aspectRatio: 16 / 9,
                  child: Center(
                    child: CircularProgressIndicator(strokeWidth: 2.0),
                  ),
                ),
        ),
      ),
    );
  }
}

注意事项(Q&A)

  • 视频如果需要横竖屏不能使用safeArea

  • 顶部控制拦或者底部控制拦文字或者图标被裁剪,调整字体或图标大小,也可以通过调整控制拦高度

  • 视频的 dataSoure不能为空,为空时使用加载视图,否则播放器会报错

    import 'package:flutter/material.dart';
    import 'package:awsome_video_player/awsome_video_player.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
    
      String videoUrl = "https://www.runoob.com/try/demo_source/movie.mp4";
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Awsome video player'),
            ),
            body: Center(
            	/// 一般videoUrl是从服务端返回,在没有返回来之前,
            	/// 我们可以使用加载视图来占位
              child: videoUrl != "" ? AwsomeVideoPlayer(
                videoUrl,
                /// 视频播放配置
                playOptions: VideoPlayOptions(
                  seekSeconds: 30,
                  aspectRatio: 16 / 9,
                  loop: true,
                  autoplay: true,
                  allowScrubbing: true,
                  startPosition: Duration(seconds: 0)),
              ) : AspectRatio(
                aspectRatio: 16 / 9,
                child: Center(
                  child: CircularProgressIndicator(strokeWidth: 2.0),
                ),
              ),
            ),
          ),
        );
      }
    }
    
  • AwsomeVideoPlayer下面的children仅支持AlignPositioned,children的层级会高于下面,这个功能会持续更新,后面会陆续出一些针对自定义拓展的高阶文档。

FAQ

  • http协议的地址播放错误?

Android9.0 (API 28)起,应用默认禁止http请求,需要在AndroidManifest.xml中配置以下内容

">
<application
	...
	android:usesCleartextTraffic="true"
	...
>

写在最后

开发过程中遇到问题,请通过以下方式联系我,我会第一时间回复你:

  • 联系我 QQ:604748948 QQ群:160612343 微信:cheampie 微信谈论组

  • Report

License

Copyright © 2020, Mark Chen. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

GitHub

https://github.com/chudongvip/awsome_video_player
Comments
  • 1. Looking up a deactivated widget's ancestor is unsafe

    ════════ Exception caught by scheduler library ═════════════════════════════════════════════════════ The following assertion was thrown during a scheduler callback: Looking up a deactivated widget's ancestor is unsafe.

    At this point the state of the widget's element tree is no longer stable.

    To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.

    When the exception was thrown, this was the stack: #0 Element._debugCheckStateIsActiveForAncestorLookup. (package:flutter/src/widgets/framework.dart:3508:9) #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3522:6) #2 Element.dependOnInheritedWidgetOfExactType (package:flutter/src/widgets/framework.dart:3564:12) #3 MediaQuery.of (package:flutter/src/widgets/media_query.dart:793:38) #4 _AwsomeVideoPlayerState.initState.. (package:awsome_video_player/src/video.dart:113:38) ... ════════════════════════════════════════════════════════════════════════════════════════════════════

    Reviewed by z234009184 at 2020-03-26 10:35
  • 2. [Bug Report]全屏报错

    系统:安卓8.0.0 插件版本:1.0.8

    E/flutter ( 4166): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method SystemChrome.forceOrientation on channel sososdk.github.com/orientation)
    
    E/flutter ( 4166): #0      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:319:7)
    
    E/flutter ( 4166):  < asynchronous suspension >
    
    E/flutter ( 4166): #1      OrientationPlugin.forceOrientation (package:orientation/orientation.dart:35:26)
    
    E/flutter ( 4166): #2      _AwsomeVideoPlayerState.toggleFullScreen (package:awsome_video_player/src/video.dart:342:25)
    
    E/flutter ( 4166): #3      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
    
    Reviewed by slimcheng at 2020-04-17 10:54
  • 3. 建议

    用了一下大佬的库, 给几点建议:

    1. 取消播放键, 因为双击就是播放键, 三个键占用的位子太挤了, 经常点不到自己想点的键, 目前我用的是改变按钮大小, 直接给播放键的size为1;
    2. 播放进度条点击的时候经常点击不到, 主要是太窄了,建议点击阴影部分也触发, 因为那部分不是经常点击,所以修改后不会影像整体的体验,反而更加方便用户想要快进到哪个点.或者直接可以自定义进度条的宽度.让用户自己控制宽度;
    3. 给是否全屏播放一个回调, 因为在一个有appBar的情况全屏播放会出现appBar,如果有回调可以隐藏appBar.

    整体感觉这个库很棒. 谢谢作者!

    Reviewed by YeFei572 at 2020-01-26 14:47
  • 4. Cannot use the package!

    Hi,

    I have successfully add this package to my project, however when I try to run the install command the following error was occurred:

    FAILURE: Build failed with an exception.

    • What went wrong: A problem occurred configuring project ':screen'.

    Could not resolve all artifacts for configuration ':screen:classpath'. Could not find gradle.jar (com.android.tools.build:gradle:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.3.1/gradle-3.3.1.jar Could not find builder.jar (com.android.tools.build:builder:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/builder/3.3.1/builder-3.3.1.jar Could not find tracker.jar (com.android.tools.analytics-library:tracker:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/tracker/26.3.1/tracker-26.3.1.jar Could not find shared.jar (com.android.tools.analytics-library:shared:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/shared/26.3.1/shared-26.3.1.jar Could not find crash.jar (com.android.tools.analytics-library:crash:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/crash/26.3.1/crash-26.3.1.jar Could not find lint-gradle-api.jar (com.android.tools.lint:lint-gradle-api:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/lint/lint-gradle-api/26.3.1/lint-gradle-api-26.3.1.jar Could not find gradle-api.jar (com.android.tools.build:gradle-api:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle-api/3.3.1/gradle-api-3.3.1.jar Could not find databinding-compiler-common.jar (androidx.databinding:databinding-compiler-common:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-compiler-common/3.3.1/databinding-compiler-common-3.3.1.jar Could not find manifest-merger.jar (com.android.tools.build:manifest-merger:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/manifest-merger/26.3.1/manifest-merger-26.3.1.jar Could not find sdk-common.jar (com.android.tools:sdk-common:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/sdk-common/26.3.1/sdk-common-26.3.1.jar Could not find builder-test-api.jar (com.android.tools.build:builder-test-api:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-test-api/3.3.1/builder-test-api-3.3.1.jar Could not find ddmlib.jar (com.android.tools.ddms:ddmlib:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/ddms/ddmlib/26.3.1/ddmlib-26.3.1.jar Could not find sdklib.jar (com.android.tools:sdklib:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/sdklib/26.3.1/sdklib-26.3.1.jar Could not find layoutlib-api.jar (com.android.tools.layoutlib:layoutlib-api:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/layoutlib/layoutlib-api/26.3.1/layoutlib-api-26.3.1.jar Could not find dvlib.jar (com.android.tools:dvlib:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/dvlib/26.3.1/dvlib-26.3.1.jar Could not find repository.jar (com.android.tools:repository:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/repository/26.3.1/repository-26.3.1.jar Could not find common.jar (com.android.tools:common:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/common/26.3.1/common-26.3.1.jar Could not find builder-model.jar (com.android.tools.build:builder-model:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/builder-model/3.3.1/builder-model-3.3.1.jar Could not find protos.jar (com.android.tools.analytics-library:protos:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/analytics-library/protos/26.3.1/protos-26.3.1.jar Could not find apkzlib.jar (com.android.tools.build:apkzlib:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/apkzlib/3.3.1/apkzlib-3.3.1.jar Could not find apksig.jar (com.android.tools.build:apksig:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/build/apksig/3.3.1/apksig-3.3.1.jar Could not find annotations.jar (com.android.tools:annotations:26.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/tools/annotations/26.3.1/annotations-26.3.1.jar Could not find databinding-common.jar (androidx.databinding:databinding-common:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/androidx/databinding/databinding-common/3.3.1/databinding-common-3.3.1.jar Could not find baseLibrary.jar (com.android.databinding:baseLibrary:3.3.1). Searched in the following locations: https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/3.3.1/baseLibrary-3.3.1.jar Could not get unknown property 'android' for project ':screen' of type org.gradle.api.Project.

    • Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

    • Get more help at https://help.gradle.org

    BUILD FAILED in 10s The built failed likely due to AndroidX incompatibilities in a plugin. The tool is about to try using Jetfier to solve the incompatibility. Building plugin awsome_video_player... Running Gradle task 'assembleAarRelease'... Unzipping /Users/alireza/.gradle/wrapper/dists/gradle-5.4.1-all/3221gyojl5jsh0helicew7rwx/gradle-5.4.1-all.zip to /Users/alireza/.gradle/wrapper/dists/gradle-5.4.1-all/3221gyojl5jsh0helicew7rwx

    Exception in thread "main" java.util.zip.ZipException: error in opening zip file at java.util.zip.ZipFile.open(Native Method) at java.util.zip.ZipFile.(ZipFile.java:225) at java.util.zip.ZipFile.(ZipFile.java:155) at java.util.zip.ZipFile.(ZipFile.java:169) at org.gradle.wrapper.Install.unzip(Install.java:214) at org.gradle.wrapper.Install.access$600(Install.java:27) at org.gradle.wrapper.Install$1.call(Install.java:74) at org.gradle.wrapper.Install$1.call(Install.java:48) at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:65) at org.gradle.wrapper.Install.createDist(Install.java:48) at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:128) at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)

    Exception: The plugin awsome_video_player could not be built due to the issue above.

    Reviewed by alr2413 at 2020-04-09 21:36
  • 5. 大佬 把控制器暴露出来啊

    image

    
      @override
      AwsomeVideoPlayerState createState() => AwsomeVideoPlayerState();
    }
    
    class AwsomeVideoPlayerState extends State<AwsomeVideoPlayer>
        with SingleTickerProviderStateMixin {
      /// 控制器 - 快进 seekTo 暂停 pause 播放 play 摧毁 dispose
      VideoPlayerController controller;
    

    有些操作要在其他地方做。不暴露出控制器 怎么搞

    Reviewed by taozhipeng1990 at 2020-06-19 03:08
  • 6. PLEASE ADD THIS FUNCTIONALITY

    1-ADD A COVER LOCK 2-GESTURE ANIMATION UI FOR BRIGHTNESS AND VOLUME 3-DEFAULT FULLSCREEN 4-WHEN PLAYER IS LOADING THEN SHOW A INTERNET SPEED FOR USER

    PLEASE ADD THESE FUNCTIONALITY BY THE WAY YOUR PACKAGE IS VERY COOL....THANKS & LOVE FROM INDIA

    Reviewed by MeTubeapp at 2020-05-18 02:51
  • 7. 切换dataSource 视频url地址无效

    您好, 当我在

    ...省略部分代码
    AwsomeVideoPlayer(
          url,
    );
    ...省略部分代码
    setState(() {
          url = "https://other_video.mp4";
    });
    

    切换url之后 视频并没有重新播放,而是接着播放之前的url链接的视频. 请问怎么操作可以切换当前的视频

    Reviewed by z234009184 at 2020-03-27 13:54
  • 8. next branch issue

    hey bro i m using ontimeupdate same as master branch in your next branch and this give me error type '(VideoPlayerValue) => Null' is not a subtype of type '(dynamic) => void' Another exception was thrown: type '(VideoPlayerValue) => Null' is not a subtype of type '(dynamic) => void' and my code is ontimeupdate: (value) { print("timeupdate $value"); var position = value.position.inMilliseconds / 1000; print(position); },

    Reviewed by MeTubeapp at 2020-06-03 04:36
  • 9. 视频可以在浏览器上播放,但是在flutter app 上不可以

    视频可以在浏览器上播放,但是在flutter app 上不可以 报错如下 flutter: 日志拦截: http://192.168.100.8:8081/file?p=/video/2020/05/IMG_3761.mp4 [VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter/src/foundation/stack_frame.dart': Failed assertion: line 113 pos 12: 'match != null': Expected to match RegExp: pattern=^(.+) (\d+):(\d+)\s+(.+)$ flags=. #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:42:39) #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:38:5) #2 StackFrame._parseWebDebugFrame (package:flutter/src/foundation/stack_frame.dart:113:12) #3 StackFrame._parseWebFrame (package:flutter/src/foundation/stack_frame.dart:99:14) #4 StackFrame.fromStackTraceLine (package:flutter/src/foundation/stack_frame.dart:193:14) #5 MappedListIterable.elementAt (dart:_internal/iterable.dart:417:31) #6 ListIterator.moveNext (dart:_internal/iterable.dart:346:26) #7 SkipWhileIterator.moveNext (dart:_internal/iterable.dart:669:24) #8 new List.from (dart:core-patch/array_patch.dart:47:19) #9 Iterable.toList (dart:core/iterable.dart:400:12) #10 StackFrame.fromStackString (package:flutter/src/foundation/stack_frame.dart:94:10) #11 FlutterError.defaultStackFilter (package:flutter/src/foundation/assertions.dart:820:54) #12 new DiagnosticsStackTrace (package:flutter/src/foundation/assertions.dart:958:59) #13 FlutterErrorDetails.debugFillProperties (package:flutter/src/foundation/assertions.dart:575:22) #14 DiagnosticableNode.builder. (package:flutter/src/foundation/diagnostics.dart:2926:18) #15 DiagnosticableNode.builder (package:flutter/src/foundation/diagnostics.dart:2929:8) #16 _FlutterErrorDetailsNode.builder (package:flutter/src/foundation/assertions.dart:996:55) #17 DiagnosticableNode.getProperties (package:flutter/src/foundation/diagnostics.dart:2943:105) #18 TextTreeRenderer._debugRender (package:flutter/src/foundation/diagnostics.dart:1238:63) #19 TextTreeRenderer.render (package:flutter/src/foundation/diagnostics.dart:1116:14) #20 DiagnosticsNode.toStringDeep. (package:flutter/src/foundation/diagnostics.dart:1730:9) #21 DiagnosticsNode.toStringDeep (package:flutter/src/foundation/diagnostics.dart:1737:6) #22 FlutterErrorDetails.toString (package:flutter/src/foundation/assertions.dart:590:65) #23 _StringBase._interpolateSingle (dart:core-patch/string_patch.dart:823:17) #24 print (dart:core/print.dart:11:26) #25 AppInit.reportErrorAndLog (package:iCloud/init/app_init.dart:44:5) #26 AppInit.catchException. (package:iCloud/init/app_init.dart:32:9) #27 _rootRunBinary (dart:async/zone.dart:1208:13) #28 _CustomZone.runBinary (dart:async/zone.dart:1093:19) #29 runZonedGuarded. (dart:async/zone.dart:1591:19) #30 _CustomZone.handleUncaughtError (dart:async/zone.dart:1059:19) #31 Future._propagateToListeners (dart:async/future_impl.dart:598:16) #32 Future._completeError (dart:async/future_impl.dart:534:5) #33 Future._asyncCompleteError. (dart:async/future_impl.dart:582:7) #34 _rootRun (dart:async/zone.dart:1184:13) #35 _CustomZone.run (dart:async/zone.dart:1077:19) #36 _CustomZone.runGuarded (dart:async/zone.dart:979:7) #37 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1019:23) #38 _microtaskLoop (dart:async/schedule_microtask.dart:43:21) #39 _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)

    代码如下:

    import 'package:flutter/material.dart'; import 'package:awsome_video_player/awsome_video_player.dart'; import 'package:iCloud/page/fintness_app_theme.dart';

    class VideoPlayPage extends StatefulWidget { const VideoPlayPage( {Key key, this.url,this.name,this.index}) : super(key: key); final String url; final String name; final int index;

    @override _VideoPlayPageState createState() => new _VideoPlayPageState(this.url,this.name,this.index); }

    class _VideoPlayPageState extends State { _VideoPlayPageState(this.url,this.name,this.index);

    final String url; final String name; final int index;

    String mainSubtitles = ""; //主字幕 String subSubtitles = ""; //辅字幕 bool _isPlaying = false; bool _isFullscreen = false;

    bool showAdvertCover = false; //是否显示广告

    bool get isPlaying => _isPlaying; set isPlaying(bool playing) { print("playing $playing"); _isPlaying = playing; }

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

    @override Widget build(BuildContext context) { print(url); return MaterialApp( home: Container( color: FintnessAppTheme.background, child: Scaffold( backgroundColor: Colors.transparent, appBar: !_isFullscreen ? AppBar( leading: IconButton(icon: new Icon(Icons.chevron_left)), backgroundColor: FintnessAppTheme.background, automaticallyImplyLeading: true, title: Text(name,style: TextStyle( color: Colors.black38 ),),

              ): null,
              body: Column(children: <Widget>[
                url != ""
                    ? AwsomeVideoPlayer(
                  "http://192.168.100.8:8081/file?p=/video/2020/05/IMG_3761.mp4",
                  /// 视频播放配置
                  playOptions: VideoPlayOptions(
                      seekSeconds: 30,
                      //左侧垂直手势调节视频亮度的单位(0~1之间,不能小于0,不能大于1)
                      brightnessGestureUnit: 0.05,
                      //右侧垂直手势调节视频音量的单位(0~1之间,不能小于0,不能大于1)
                      volumeGestureUnit: 0.05,
                      //横行手势调节视频进度的单位秒数
                      progressGestureUnit: 2000,
                      aspectRatio: 16 / 9,
                      loop: false,
                      autoplay: true,
                      allowScrubbing: true,
                      startPosition: Duration(seconds: 0)),
    
                  /// 自定义视频样式
                  videoStyle: VideoStyle(
                    /// 自定义视频暂停时视频中部的播放按钮
                    playIcon: Icon(
                      Icons.play_circle_outline,
                      size: 80,
                      color: Colors.white,
                    ),
    
                    /// 暂停时是否显示视频中部播放按钮
                    showPlayIcon: true,
    
                    videoLoadingStyle: VideoLoadingStyle(
                      /// 重写部分(二选一)
                      // 重写Loading的widget
                      // customLoadingIcon: CircularProgressIndicator(strokeWidth: 2.0),
                      // 重写Loading 下方的Text widget
                      // customLoadingText: Text("加载中..."),
                      /// 设置部分(二选一)
                      // 设置Loading icon 下方的文字
                      loadingText: "Loading...",
                      // 设置loading icon 下方的文字颜色
                      loadingTextFontColor: Colors.white,
                      // 设置loading icon 下方的文字大小
                      loadingTextFontSize: 20,
                    ),
    
                    /// 自定义顶部控制栏
                    videoTopBarStyle: VideoTopBarStyle(
                      show: true, //是否显示
                      height: 40,
                      padding:
                      EdgeInsets.symmetric(vertical: 8, horizontal: 10),
                      barBackgroundColor: Color.fromRGBO(0, 0, 0, 0.5),
                      popIcon: Icon(
                        Icons.arrow_back,
                        size: 16,
                        color: Colors.white,
                      ),
    

    // contents: [ // Center( // child: Container( // margin: EdgeInsets.symmetric(horizontal: 10), // child: Text( // '返回', // style: TextStyle( // color: Colors.white, fontSize: 14), // ), // ), // ) // ], //自定义顶部控制栏中间显示区域 // actions: [ // GestureDetector( // onTap: () { // ///1. 可配合自定义拓展元素使用,例如广告 // setState(() { // showAdvertCover = true; // }); // // /// // }, // child: Icon( // Icons.more_horiz, // size: 16, // color: Colors.white, // ), // ) // ], //自定义顶部控制栏右侧显示区域 /// 设置cusotmBar之后,以上属性均无效(除了show之外) // customBar: Positioned( // top: 0, // left: 0, // right: 0, // child: Container( // width: double.infinity, // height: 50, // color: Colors.yellow, // child: Text("12312312"), // ), // ), // customBar: Align( // alignment: Alignment.topLeft, // child: Container( // width: double.infinity, // height: 30, // color: Colors.yellow, // child: GestureDetector( // onTap: () { // print("yes"); // }, // child: Text("123123132") // ) // ), // ), ),

                    /// 自定义底部控制栏
                    videoControlBarStyle: VideoControlBarStyle(
                      /// 自定义颜色
                      // barBackgroundColor: Colors.blue,
    
                      ///添加边距
                      padding:
                      EdgeInsets.symmetric(vertical: 8, horizontal: 10),
    
                      ///设置控制拦的高度,默认为30,如果图标设置过大但是高度不够就会出现图标被裁剪的现象
                      height: 30,
    
                      /// 自定义进度条样式
                      // progressStyle: VideoProgressStyle(
                      //     // padding: EdgeInsets.all(0),
                      //     padding: EdgeInsets.symmetric(
                      //         vertical: 0,
                      //         horizontal: 10), //vertical不能设置太大,不然被把进度条压缩肉眼无法识别
                      //     playedColor: Colors.red,
                      //     bufferedColor: Colors.yellow,
                      //     backgroundColor: Colors.green,
                      //     dragBarColor: Colors
                      //         .white, //进度条为`progress`时有效,如果时`basic-progress`则无效
                      //     height: 4,
                      //     progressRadius:
                      //         2, //进度条为`progress`时有效,如果时`basic-progress`则无效
                      //     dragHeight:
                      //         5 //进度条为`progress`时有效,如果时`basic-progress`则无效
                      //     ),
    
                      /// 更改进度栏的播放按钮
                      playIcon: Icon(Icons.play_arrow,
                          color: Colors.white, size: 16),
    
                      /// 更改进度栏的暂停按钮
                      pauseIcon: Icon(
                        Icons.pause,
                        color: Colors.white,
                        size: 16,
                      ),
    
                      /// 更改进度栏的快退按钮
                      rewindIcon: Icon(
                        Icons.replay_30,
                        size: 16,
                        color: Colors.white,
                      ),
    
                      /// 更改进度栏的快进按钮
                      forwardIcon: Icon(
                        Icons.forward_30,
                        size: 16,
                        color: Colors.white,
                      ),
    
                      /// 更改进度栏的全屏按钮
                      fullscreenIcon: Icon(
                        Icons.fullscreen,
                        size: 20,
                        color: Colors.white,
                      ),
    
                      /// 更改进度栏的退出全屏按钮
                      fullscreenExitIcon: Icon(
                        Icons.fullscreen_exit,
                        size: 20,
                        color: Colors.red,
                      ),
    
                      /// 决定控制栏的元素以及排序,示例见上方图3
                      itemList: [
                        "rewind",
                        "play",
                        "forward",
                        "position-time", //当前播放时间
                        "progress", //线条形进度条(与‘basic-progress’二选一)
                        // "basic-progress",//矩形进度条(与‘progress’二选一)
                        "duration-time", //视频总时长
                        // "time",//格式:当前时间/视频总时长
                        "fullscreen"
                      ],
                    ),
    
                    /// 自定义字幕
                    videoSubtitlesStyle: VideoSubtitles(
                      mianTitle: Align(
                        alignment: Alignment.bottomCenter,
                        child: Container(
                          padding: EdgeInsets.fromLTRB(10, 0, 10, 30),
                          child: Text(mainSubtitles,
                              maxLines: 2,
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                  color: Colors.white, fontSize: 14)),
                        ),
                      ),
                      subTitle: Align(
                        alignment: Alignment.bottomCenter,
                        child: Container(
                          padding: EdgeInsets.all(10),
                          child: Text(subSubtitles,
                              maxLines: 2,
                              textAlign: TextAlign.center,
                              style: TextStyle(
                                  color: Colors.white, fontSize: 14)),
                        ),
                      ),
                    ),
                  ),
    
                  /// 自定义拓展元素
                  children: [
                    /// DEMO1 自定义视频播放状态Toast
                    /// 待完善
    
                    /// DEMO2 这个将会覆盖的视频内容,因为这个层级是最高级,因此手势会失效(慎用)
                    /// 这个可以用来做视频广告
                    showAdvertCover
                        ? Align(
                      alignment: Alignment.center,
                      child: Container(
                        width: 200,
                        height: 100,
                        color: Colors.blue[500],
                        child: Stack(
                          fit: StackFit.expand,
                          children: <Widget>[
                            //关闭广告
                            Align(
                              alignment: Alignment.topRight,
                              child: GestureDetector(
                                onTap: () {
                                  setState(() {
                                    showAdvertCover = false;
                                  });
                                },
                                child: Icon(
                                  Icons.cancel,
                                  size: 16,
                                  color: Colors.white,
                                ),
                              ),
                            ),
                            Container(
                              alignment: Alignment.center,
                              child: Text(
                                "一个广告封面",
                                style: TextStyle(color: Colors.white),
                              ),
                            )
                          ],
                        ),
                      ),
                    )
                        : Align(),
                  ],
    
                  /// 视频暂停回调
                  onpause: (value) {
                    print("video paused");
                    setState(() {
                      isPlaying = false;
                    });
                  },
    
                  /// 视频播放回调
                  onplay: (value) {
                    print("video played");
                    setState(() {
                      isPlaying = true;
                    });
                  },
    
                  /// 视频播放结束回调
                  onended: (value) {
                    print("video ended");
                  },
    
                  /// 视频播放进度回调
                  /// 可以用来匹配字幕
                  ontimeupdate: (value) {
                    // print("timeupdate ${value}");
                    // var position = value.position.inMilliseconds / 1000;
                    //根据 position 来判断当前显示的字幕
                  },
    
                  onprogressdrag: (position, duration) {
                    print("进度条拖拽的时间节点: ${position}");
                    print("进度条总时长: ${duration}");
                  },
    
                  onvolume: (value) {
                    print("onvolume ${value}");
                  },
    
                  onbrightness: (value) {
                    print("onbrightness ${value}");
                  },
    
                  onfullscreen: (fullscreen) {
                    print("is fullscreen $fullscreen");
                    setState(() {
                      _isFullscreen = fullscreen;
                    });
                  },
    
                  /// 顶部控制栏点击返回按钮
                  onpop: (value) {
                    print("返回上一页");
                    Navigator.of(context).pop(0);
                  },
                )
                    : AspectRatio(
                  aspectRatio: 16 / 9,
                  child: Center(
                    child: CircularProgressIndicator(strokeWidth: 2.0),
                  ),
                ),
              ])),
        ));
    

    } }

    Reviewed by markchao at 2020-05-27 15:13
  • 10. 无法构建插件。。最新版

    使用的是vscode

    FAILURE: Build failed with an exception.

    • What went wrong: Execution failed for task ':awsome_video_player:packageDebugAssets'.

    Failed to create directory 'H:\helloworld\build\awsome_video_player\intermediates\incremental\packageDebugAssets'

    • Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

    • Get more help at https://help.gradle.org

    BUILD FAILED in 7s

    Reviewed by tiantianaixuexi at 2020-04-10 05:31
  • 11. Question

    I have a list of video urls as a listview and onTap i want to load the player with new url, i tried setstate, changeNotifier, but its not working, can you help please?

    Reviewed by SdxCoder at 2020-03-15 16:57
  • 12. 播放本地文件的时候,好像有些问题

    我在使用“/storage/emulated/0/Android/data/…………”地址播放文件的时候 尝试了以下三种方式都不行, AwsomeVideoPlayer("/storage/emulated/0/Android/data/…………") AwsomeVideoPlayer(file://storage/emulated/0/Android/data/…………) AwsomeVideoPlayer(File("/storage/emulated/0/Android/data/…………"))

    看了一下源代码是是用正则去判断资源类型的 final fileRegx = new RegExp(r'^(file)://([\w.]+/?)\S*'); final isFile = fileRegx.hasMatch(widget.dataSource); 如果isFile是true 则执行 VideoPlayerController.file(widget.dataSource); 但是file点进去入参是需要一个File类型。

    是我的使用方法有误吗 ?

    我尝试了以下解决方法 添加一个DataSourceType 字段 ,在创建AwsomeVideoPlayer组件的时候,传入资源类型 然后修改了createVideoPlayerController 方法。

      /// 创建video controller
      VideoPlayerController createVideoPlayerController() {
        // final netRegx = new RegExp(r'^(http|https):\/\/([\w.]+\/?)\S*');
        // final fileRegx = new RegExp(r'^(file):\/\/([\w.]+\/?)\S*');
        // final isFile = widget.dataSource is File;
        // final isNetwork = netRegx.hasMatch(widget.dataSource);
        // final isFile = fileRegx.hasMatch(widget.dataSource); 2020-9-30 04:37:23
        // if (isNetwork) {
        //   return VideoPlayerController.network(widget.dataSource);
        // } else if (isFile) {
        //   return VideoPlayerController.file(widget.dataSource);
        // } else {
        //   return VideoPlayerController.asset(widget.dataSource);
        // }
        switch(widget.dataSourceType){
          case AwsomeVideoPlayer.netDataSourceType:
            return VideoPlayerController.network(widget.dataSource);
          case AwsomeVideoPlayer.fileDataSourceType:
            return VideoPlayerController.file(widget.dataSource);
          case AwsomeVideoPlayer.assetDataSourceType:
            return VideoPlayerController.asset(widget.dataSource);
        }
    
      }
    
    Reviewed by gotosleep7 at 2020-10-01 16:36

Related

Better video player for Flutter, with multiple configuration options. Solving typical use cases!
Better video player for Flutter, with multiple configuration options. Solving typical use cases!

Better video player for Flutter, with multiple configuration options. Solving typical use cases!

May 23, 2022
Flutter-Music-Player - A simple music player app that let you play mp3 songs with some customization feature with a rich user interface
Flutter-Music-Player - A simple music player app that let you play mp3 songs with some customization feature with a rich user interface

Flutter-Music-Player - A simple music player app that let you play mp3 songs with some customization feature with a rich user interface

Feb 10, 2022
Flutter Music Player - A complete and open source music player designed in flutter.
 Flutter Music Player - A complete and open source music player designed in flutter.

Flutter Music Player A complete and open source music player designed in flutter. It is first complete music player designed in flutter. This app expl

Jan 9, 2022
Advanced video player based on video_player and Chewie for flutter
Advanced video player based on video_player and Chewie for flutter

Better Player Advanced video player based on video_player and Chewie. It's solves many typical use cases and it's easy to run. Introduction This plugi

Dec 22, 2021
The video player for Flutter with a heart of gold

chewie The video player for Flutter with a heart of gold. The video_player plugin provides low-level access to video playback. Chewie uses the video_p

May 21, 2022
Flutter plugin for use Video.js in flutter web
Flutter plugin for use Video.js in flutter web

Flutter Video.js player Flutter plugin for use Video.js in flutter web Installation Add it to your package's pubspec.yaml file dependencies: video_j

Apr 23, 2022
A simple music player made using Flutter.
A simple music player made using Flutter.

Music Player App This is a beautiful music player, developed using Flutter. Features Play any song included in Flutter Assets Background Play Beautifu

Apr 24, 2022
Flutter video trimmer package
Flutter video trimmer package

A Flutter package for trimming videos Features Customizable video trimmer Video playback control Retrieving and storing video file Also, supports conv

May 14, 2022
A simple video streaming application made with Dart, JavaScript, HTML, CSS
A simple video streaming application made with Dart, JavaScript, HTML, CSS

streamZ A simple video streaming application made with Dart, JS, HTML, CSS & ❤️ Show some ❤️ by putting ⭐ Recently I wrote an article, explaining how

Nov 23, 2021
Image Editor Plugin with simple, easy support for image editing using Paints, Text, Filters, Emoji and Sticker like stories.
Image Editor Plugin with simple, easy support for image editing using Paints, Text, Filters, Emoji and Sticker like stories.

ImageEditorPro Image Editor Plugin with simple, easy support for image editing using Paints, Text, Filters, Emoji and Sticker like stories. To start w

May 15, 2022
Flutter plugin for sound. Audio recorder and player.
Flutter plugin for sound. Audio recorder and player.

Flutter Sound user: your documentation is there The CHANGELOG file is here Overview Flutter Sound is a Flutter package allowing you to play and record

May 21, 2022
Flutter plugin for sound. Audio recorder and player.
Flutter plugin for sound. Audio recorder and player.

Sounds Sounds is a Flutter package allowing you to play and record audio for both the android and ios platforms. Sounds provides both a high level API

May 5, 2022
A Flutter media player plugin for iOS and android based on ijkplayer
A Flutter media player plugin for iOS and android based on ijkplayer

Flutter media player plugin for android/iOS based on ijkplayer.

May 24, 2022
Official Flutter SDK for LiveKit. Easily add real-time video and audio to your Flutter apps.

LiveKit Flutter SDK Official Flutter SDK for LiveKit. Easily add real-time video and audio to your Flutter apps. This package is published to pub.dev

May 18, 2022
Music Player app made with Just audio library and Local database Hive.
Music Player app made with Just audio library and Local database Hive.

Music Player app made with Just audio library and Local database Hive. Find the free and Royelty music with Happy Rock application. The app contains information about singers and you can make your own playlist with Songs.Happy rock App's features are same as the real music app like spotify, amazon music etc.

Mar 30, 2022
An online and offline music player

awesomemusic A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

Jan 18, 2022
Just_audio: a feature-rich audio player for Android, iOS, macOS and web
Just_audio: a feature-rich audio player for Android, iOS, macOS and web

just_audio just_audio is a feature-rich audio player for Android, iOS, macOS and web. Mixing and matching audio plugins The flutter plugin ecosystem c

Feb 2, 2022
A opensource, minimal and powerful audio player for android

A opensource, minimal and powerful audio player for android

Feb 7, 2022
video call with WebRTC and Flutter
video call with WebRTC and Flutter

Video Call Flutter App ?? Description: This is sandbox video call application using Flutter and WebRTC, you can call from browser to browser, phone to

Apr 27, 2022