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 % 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(“
@override void dispose() { /// 关闭监听 player.removeListener(_playerValueChanged); /// 关闭流回调 _currentPosSubs?.cancel(); super.dispose(); } }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/234057.html原文链接:https://javaforall.cn
相关文章
- Flutter 使用插件打开相册、相机「建议收藏」
- flutter系列之:Material主题的基础-MaterialApp
- 【Flutter桌面篇】Flutter&Windows应用尝鲜
- flutter中的包管理与资源管理
- 2022-01-17: flutter weekly第3期
- 为什么flutter可以跨平台
- flutter系列之:Navigator的高级用法
- 2020年Flutter和 React Native如何选择
- flutter 报错解决
- Flutter 耗时监控 | 路由名为空原因分析
- Flutter 3.7 新特性:介绍后台isolate通道
- flutter系列之:创建一个内嵌的navigation
- 【Flutter】Flutter 打开第三方应用 ( url_launcher 插件搜索与安装 | url_launcher 插件官方示例 | 打开浏览器 | 打开第三方应用 )
- 【Flutter】Flutter 应用主题 ( ThemeData | 动态修改主题 )
- 【错误记录】Flutter 报错 ( Could not read script ‘xxxflutter_toolsgradleapp_plugin_loader.gradle‘ )
- 【错误记录】Flutter 报错 ( Because xx depends on flutter_driver any from sdk which depends on args 1.6.0 )
- Flutter 3.3发布,带来新的预览版渲染引擎
- 【Flutter】Flutter 混合开发 ( 混合开发中 Flutter 的 热重启 / 热加载 )
- 【错误记录】Flutter 混合开发报错 ( Android 端与 Flutter 端 EventChannel 初始化顺序错误导致无法通信 | EventChannel 通信流程 )
- 在 Flutter 移动应用程序中创建一个列表