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();
}
}
文章浏览阅读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语言
文章浏览阅读3.3k次,点赞4次,收藏18次。**实现业务系统中的用户权限管理** B/S系统中的权限比C/S中的更显的重要,C/S系统因为具有特殊的客户端,所以访问用户的权限检测可以通过客户端实现或通过客户端+服务器检测实现,而B/S中,浏览器是每一台计算机都已具备的,如果不建立一个完整的权限检测,那么一个“非法用户”很可能就能通过浏览器轻易访问到B/S系统中的所有功能。因此B/S业务系统都需要有一个或多个权限系统来实现访问权限检测,让经过授权的用户可以正常合法的使用已授权功能,而对那些未经授权的“非法用户”将会将他们彻底的“拒之门外”。下面就让_java角色的权限分配
文章浏览阅读392次,点赞4次,收藏10次。探索React Native的多滑块组件:react-native-multi-slider项目地址:https://gitcode.com/ptomasroos/react-native-multi-slider在这个移动应用开发日益复杂的年代,寻找一个高效、灵活且易于使用的组件库是至关重要的。今天我们要介绍的是react-native-multi-slider,这是一个专门为React N...
文章浏览阅读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
文章浏览阅读2.1k次。由于C语言的灵活和设计上的追求高效率,在写C程序的时候,经常会语法正确,但隐含逻辑错误。比如变量未初始化,switch语句没有default分支等。运用C语言编译器的编译选项,也可以一定程度上发现隐含的逻辑错误。下面我们以gcc编译器为例,_wuninitialized
文章浏览阅读1.6k次,点赞6次,收藏13次。HTML表单有两种提交方式:GET方式和POST方式。表单提交方式由标签的method属性决定。method="get"是GET方式,method="post"是POST方式。另外,标签的action属性指定表单要提交到哪个页面上。如果action为空字符串"",那么就是提交到当前页面上。GET方式提交表单后,所有带有name属性的表单控件的内容都会出现在URL(浏览器网址)上,也就是说GET方式其实就是以URL参数的方式提交表单,这个之前已经讲过了。_lwip post
文章浏览阅读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、上传成功后,您可以在上传的页面中找到您上传的商品,或者您可以点击删除商品选项,选择要删除的商品。 ._拼多多一户能做几个产品吗?
文章浏览阅读1.3k次。为了解决 HTTP/1.0 存在的资源浪费的问题, HTTP/1.1 优化为默认长连接模式。_curl断点续传
文章浏览阅读102次。何为成长?成长是指自我提升,一方面是本身的个人能力,另一方面是社会对你的认可度。最终,程序员的职位和薪水都能在成长中得以体现。很多人对成长有误解,在他们眼中,随着工作年限的提高,成长是理所当然的事情,这其实是一个误区。两个程序员同时工作3年,难道他们两个的成长就完全一样吗?其实是不一样的。很多岗位在招聘的时候都要求3年以上工作经验,这个3年工作经验是指持续成长的三年,而不是指浑浑噩噩混日子的三年。下面举个通俗易懂的例子,大家一定能理解。面试经历1.偶然看到知乎的内推帖,投了个简历,下午hr姐姐ca._apk分析的试题
文章浏览阅读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.核心语句
文章浏览阅读353次。【代码】js数组抽希(无论length多长,最后都拿到100条左右数据)_javascript 点抽稀