flutter 视频播放器 FijkPlayer视频播放器的使用_flutter fijkplayer 显示控制器-程序员宅基地

技术标签: flutter  Flutter  

FijkPlayer 第三方的一个视频播放器,这是一个大佬基于比利比利播放器封装的,有常用的API 可自定义样式
pub传送门

默认的样式 展示:

自定义的样式 展示:

**使用:**
fijkplayer: ^0.8.4

/// 声明一个FijkPlayer
final FijkPlayer player = FijkPlayer();
  @override
  void initState() {
    
  	/// 指定视频地址
	player.setDataSource("http://video.kekedj.com/20190215/mp4/20190527/TWICE%20-%20BDZ%20(Korean%20Ver.)%20(Stage%20Mix)%EF%BC%88%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%AD%97%E5%B9%95%EF%BC%89.mp4", autoPlay: true);
    super.initState();

  }
  @override
  void dispose() {
    
    super.dispose();
    player.release();
  }
  
/// 使用FijkView
body: SafeArea(child: Center(
        child: FijkView(
          color: Colors.black,
          player: player,
          panelBuilder:  (FijkPlayer player, FijkData data, BuildContext context, Size viewSize, Rect texturePos) {
    
            /// 使用自定义的布局
            return CustomFijkPanel(
              player: player,
              buildContext: context,
              viewSize: viewSize,
              texturePos: texturePos,
            );
          },
        ),
      ),),

自定义的底部


class CustomFijkWidgetBottom extends StatefulWidget {
    
  final FijkPlayer player;
  final BuildContext buildContext;
  final Size viewSize;
  final Rect texturePos;

  const CustomFijkPanel({
    
    @required this.player,
    this.buildContext,
    this.viewSize,
    this.texturePos,
  });

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

class _CustomFijkWidgetBottomState extends State<CustomFijkWidgetBottom > {
    

  FijkPlayer get player => widget.player;
  /// 播放状态
  bool _playing = false;
  /// 是否显示状态栏+菜单栏
  bool isPlayShowCont = true;
  /// 总时长
  String duration = "00:00:00";
  /// 已播放时长
  String durrentPos = "00:00:00";
  /// 进度条总长度
  double maxDurations = 0.0;
  /// 流监听器
  StreamSubscription _currentPosSubs;
  /// 定时器
  Timer _timer;
  /// 进度条当前进度
  double sliderValue = 0.0;

  @override
  void initState() {
    
    /// 提前加载
    /// 进行监听
    widget.player.addListener(_playerValueChanged);
    /// 接收流
    _currentPosSubs = widget.player.onCurrentPosUpdate.listen((v) {
    
      setState(() {
    
        /// 实时获取当前播放进度(进度条)
        this.sliderValue = v.inMilliseconds.toDouble();
        /// 实时获取当前播放进度(数字展示)
        durrentPos = v.toString().substring(0,v.toString().indexOf("."));
      });
    });
    /// 初始化
    super.initState();
  }

  /// 监听器
  void _playerValueChanged() {
    
    FijkValue value = player.value;
    /// 获取进度条总时长
    maxDurations = value.duration.inMilliseconds.toDouble();
    /// 获取展示的时长
    duration = value.duration.toString().substring(0,value.duration.toString().indexOf("."));
    /// 播放状态
    bool playing = (value.state == FijkState.started);
    if (playing != _playing) setState(() =>_playing = playing);
  }

  @override
  Widget build(BuildContext context) {
    
    Rect rect = Rect.fromLTRB(
        max(0.0, widget.texturePos.left),
        max(0.0, widget.texturePos.top),
        min(widget.viewSize.width, widget.texturePos.right),
        min(widget.viewSize.height, widget.texturePos.bottom),
    );

    return Positioned.fromRect(
      rect: rect,
      child: GestureDetector(
        onTap: (){
    
          setState(() {
    
            /// 显示 、隐藏  进度条+标题栏
            isPlayShowCont = !isPlayShowCont;
            /// 如果显示了  , 3秒后 隐藏进度条+标题栏
            if(isPlayShowCont) _timer = Timer(Duration(seconds: 3),()=>isPlayShowCont = false);
          });
        },
        child:Container(
          color: Color.fromRGBO(0, 0, 0, 0.0),
            alignment: Alignment.bottomLeft,
            child:Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                /// 标题栏
                !isPlayShowCont ? SizedBox() :Container(
                  color: Color.fromRGBO(0, 0, 0, 0.65),
                  height: 35,
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      IconButton(icon: Icon(Icons.chevron_left,color: Colors.white,), onPressed: (){
    
                        Navigator.pop(context);
                      }),

                    ],
                  ),
                ),
                /// 控制条
                !isPlayShowCont ? SizedBox() : Container(
                  color: Color.fromRGBO(0, 0, 0, 0.65),
                  height: 50,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      IconButton(
                        icon: Icon(
                          _playing ? Icons.pause : Icons.play_arrow,
                          color: Colors.white,
                        ),
                        onPressed: () => _playing ? widget.player.pause() : widget.player.start(),
                      ),
                      /// 进度条 使用Slider滑动组件实现
                      Expanded(child: SliderTheme(
                        data: SliderTheme.of(context).copyWith(
                          //已拖动的颜色
                          activeTrackColor: Colors.greenAccent,
                          //未拖动的颜色
                          inactiveTrackColor: Colors.green,
                          //提示进度的气泡的背景色
                          valueIndicatorColor: Colors.green,
                          //提示进度的气泡文本的颜色
                          valueIndicatorTextStyle: TextStyle(
                            color:Colors.white,
                          ),
                          //滑块中心的颜色
                          thumbColor: Colors.green,
                          //滑块边缘的颜色
                          overlayColor: Colors.white,
                          //对进度线分割后,断续线中间间隔的颜色
                          inactiveTickMarkColor: Colors.white,
                        ),
                        child: Slider(
                          value: this.sliderValue,
                          label: '${int.parse((this.sliderValue  / 3600000).toStringAsFixed(0))<10?'0'+(this.sliderValue  / 3600000).toStringAsFixed(0):(this.sliderValue  / 3600000).toStringAsFixed(0)}:${int.parse(((this.sliderValue  % 3600000) /  60000).toStringAsFixed(0))<10?'0'+((this.sliderValue  % 3600000) /  60000).toStringAsFixed(0):((this.sliderValue  % 3600000) /  60000).toStringAsFixed(0)}:${int.parse(((this.sliderValue  % 60000) /  1000).toStringAsFixed(0))<10?'0'+((this.sliderValue % 60000) /  1000).toStringAsFixed(0):((this.sliderValue  % 60000) /  1000).toStringAsFixed(0)}',
                          min: 0.0,
                          max: maxDurations,
                          divisions: 1000,
                          onChanged: (val){
    
                            ///转化成double
                            setState(() => this.sliderValue = val.floorToDouble());
                            /// 设置进度
                            player.seekTo(this.sliderValue.toInt());
//                            print(this.sliderValue);
                          },
                        ),
                      ),
                      ),
                      Text("${durrentPos} / ${duration}",style: TextStyle(color: Colors.white),),
                    ],
                  ),
                ),
              ],
            )
        ),
      ),
    );
  }

  @override
  void dispose() {
    
    /// 关闭监听
    player.removeListener(_playerValueChanged);
    /// 关闭流回调
    _currentPosSubs?.cancel();
    super.dispose();
  }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_38025168/article/details/106482681

智能推荐

c语言实训教程答案pg2201,C语言实验十综合练习.pdf-程序员宅基地

文章浏览阅读540次。C语言实验十综合练习模拟试题一一、选择题(每题1分 共15分)1.设x,y为float型变量,则下列(A )为不合适的赋值语句A. ++x; B. y=(float)3;C. x=y=0; D. x*=y+8;注:x没有初始值,++x时会出错。y=float(3)是c++写法,给一个类型加上括号,表示强制转换。浮点型数据不能用于取模(%)运算,只有整型才可以。2. x为int 变..._pg考试c语言

【转载】JAVA用户角色权限设计(功能权限)_java角色的权限分配-程序员宅基地

文章浏览阅读3.3k次,点赞4次,收藏18次。**实现业务系统中的用户权限管理** B/S系统中的权限比C/S中的更显的重要,C/S系统因为具有特殊的客户端,所以访问用户的权限检测可以通过客户端实现或通过客户端+服务器检测实现,而B/S中,浏览器是每一台计算机都已具备的,如果不建立一个完整的权限检测,那么一个“非法用户”很可能就能通过浏览器轻易访问到B/S系统中的所有功能。因此B/S业务系统都需要有一个或多个权限系统来实现访问权限检测,让经过授权的用户可以正常合法的使用已授权功能,而对那些未经授权的“非法用户”将会将他们彻底的“拒之门外”。下面就让_java角色的权限分配

探索React Native的多滑块组件:react-native-multi-slider-程序员宅基地

文章浏览阅读392次,点赞4次,收藏10次。探索React Native的多滑块组件:react-native-multi-slider项目地址:https://gitcode.com/ptomasroos/react-native-multi-slider在这个移动应用开发日益复杂的年代,寻找一个高效、灵活且易于使用的组件库是至关重要的。今天我们要介绍的是react-native-multi-slider,这是一个专门为React N...

Atcoder Keyence Programming Contest 2020 D - Swap and Flip-程序员宅基地

文章浏览阅读550次。Atcoder Keyence Programming Contest 2020 D - Swap and Flip题目描述Solution写了一个简单的O(2nn(n+w))O(2^nn(n+w))O(2nn(n+w))的状压DP做法,正解似乎是O(2nn2)O(2^nn^2)O(2nn2)的,但也能过。设我们的方案是At1,At2,...,AtnA_{t_1},A_{t_2},...,..._keyence programming contest 2020 d

用编译选项帮你挑错_wuninitialized-程序员宅基地

文章浏览阅读2.1k次。由于C语言的灵活和设计上的追求高效率,在写C程序的时候,经常会语法正确,但隐含逻辑错误。比如变量未初始化,switch语句没有default分支等。运用C语言编译器的编译选项,也可以一定程度上发现隐含的逻辑错误。下面我们以gcc编译器为例,_wuninitialized

lwip-2.1.3自带的httpd网页服务器使用教程(四)POST类型表单的解析和文件上传_lwip post-程序员宅基地

文章浏览阅读1.6k次,点赞6次,收藏13次。HTML表单有两种提交方式:GET方式和POST方式。表单提交方式由标签的method属性决定。method="get"是GET方式,method="post"是POST方式。另外,标签的action属性指定表单要提交到哪个页面上。如果action为空字符串"",那么就是提交到当前页面上。GET方式提交表单后,所有带有name属性的表单控件的内容都会出现在URL(浏览器网址)上,也就是说GET方式其实就是以URL参数的方式提交表单,这个之前已经讲过了。_lwip post

随便推点

使用mqtt协议 硬件对接_mqtt怎么对接硬件-程序员宅基地

文章浏览阅读5k次。Shaocheng.LiToggle main menu visibility首页关于MQTT 协议和 mosquitto2015-08-11 Network 12792MQTT 介绍Mosquitto安全性3.1. SSL/TLS3.2. WebSockets with SSL/TLSlibmosquitto 库4.1. 获取库版本4.2. 初始化和清除4.3..._mqtt怎么对接硬件

店盈通:拼多多一个店铺推几个产品最好_拼多多一户能做几个产品吗?-程序员宅基地

文章浏览阅读1.5k次。  在拼多多店铺上面上架商品,那肯定也需要了解到底维持多少的数量合适。那么拼多多店铺商品数量多少合适?越多越好吗?下面店盈通给大家讲述一下。  1、输入账号名,点击保存,选择已配置的店铺,或者在开始页面配置店铺。  2、输入商品地址,可以同时输入不同的拼多多商品地址。  3、填写需要填写的相关信息。  4、选中要上传的商品,点击上传商品。如果有传错了可以点击删除商品。  5、上传成功后,您可以在上传的页面中找到您上传的商品,或者您可以点击删除商品选项,选择要删除的商品。  ._拼多多一户能做几个产品吗?

curl断点续传杂记-程序员宅基地

文章浏览阅读1.3k次。为了解决 HTTP/1.0 存在的资源浪费的问题, HTTP/1.1 优化为默认长连接模式。_curl断点续传

apk开发学习!目前最全的《Android面试题及解析》!深度好文_apk分析的试题-程序员宅基地

文章浏览阅读102次。何为成长?成长是指自我提升,一方面是本身的个人能力,另一方面是社会对你的认可度。最终,程序员的职位和薪水都能在成长中得以体现。很多人对成长有误解,在他们眼中,随着工作年限的提高,成长是理所当然的事情,这其实是一个误区。两个程序员同时工作3年,难道他们两个的成长就完全一样吗?其实是不一样的。很多岗位在招聘的时候都要求3年以上工作经验,这个3年工作经验是指持续成长的三年,而不是指浑浑噩噩混日子的三年。下面举个通俗易懂的例子,大家一定能理解。面试经历1.偶然看到知乎的内推帖,投了个简历,下午hr姐姐ca._apk分析的试题

Kodi ——6 Controls (13)6.13 Text Box_text to display goes here.核心语句-程序员宅基地

文章浏览阅读275次。6.13 Text Box 文本框用于显示XBMC多页文字。您可以选择的位置,大小,外观。6.13.1 Example My first text box control 80 60 250 200 true FFFFFFFF font13 FFFFFFFF 13 200 !Control_text to display goes here.核心语句

js数组抽希(无论length多长,最后都拿到100条左右数据)_javascript 点抽稀-程序员宅基地

文章浏览阅读353次。【代码】js数组抽希(无论length多长,最后都拿到100条左右数据)_javascript 点抽稀

推荐文章

热门文章

相关标签