使用 FijkPlayer 播放视频,包括的功能:亮度调节,音量调节,长按2倍速播放,双击暂停/开始,全屏播放。大概的效果图:
下载链接:
优快云 :flutter_blbl.zip-Android文档类资源-优快云下载
GitHub:https://github.com/wuqingsen/FlutterLearnDemo
用到的插件,网格布局,图片加载缓存淡入效果,视频播放器,音量和亮度控制器:
flutter_staggered_grid_view: ^0.4.1
transparent_image: ^2.0.0
cached_network_image: ^2.5.0
fijkplayer: ^0.10.1
volume_controller: ^2.0.2
screen_brightness: ^0.0.2
卡片效果:
封装了一个 video_card.dart :
import 'package:flutter/material.dart';
import 'package:flutter_blbl/model/base/stateful_widget_base.dart';
import 'package:flutter_blbl/model/bean/home_page_bean.dart';
import 'package:flutter_blbl/model/navigator/my_navigator.dart';
import 'package:flutter_blbl/utils/view_util.dart';
class VideoCard extends BaseWidget {
final HomePageBean homePageBean;
VideoCard({this.homePageBean});
@override
_VideoCard createState() => _VideoCard();
@override
BaseWidgetState getState() {
return _VideoCard();
}
}
class _VideoCard extends BaseWidgetState<VideoCard> {
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
MyNavigator.getInstance().onJumpTo(RouteStatus.detail,
args: {"videoMo": widget.homePageBean});
},
child: SizedBox(
height: 200,
child: Card(
margin: EdgeInsets.only(left: 4, right: 4, bottom: 8),
//阴影颜色
color: Colors.white,
//阴影高度
elevation: 1.0,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5)),
child: Column(
children: [
_itemImage(context),
_infoText(),
],
),
),
),
));
}
_itemImage(BuildContext context) {
final size = MediaQuery.of(context).size;
return Stack(
children: [
cachedImage(
widget.homePageBean.imageurl,
height: 120,
width: size.width / 2 - 20,
),
//left: 0, right: 0, bottom: 0 在下面并且左右填满
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
padding: EdgeInsets.only(left: 8, right: 8, bottom: 3, top: 5),
//线性渐变
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [Colors.black54, Colors.transparent]),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_iconText(Icons.ondemand_video, widget.homePageBean.playnum),
_iconText(Icons.favorite_border, widget.homePageBean.playnum),
_iconText(null, widget.homePageBean.videoLength),
],
),
))
],
);
}
_iconText(IconData iconData, String playnum) {
return Row(
children: [
if (iconData != null)
Icon(
iconData,
color: Colors.white,
size: 12,
),
Padding(
padding: EdgeInsets.only(left: 3, bottom: 3),
child: Text(
playnum,
style: TextStyle(color: Colors.white, fontSize: 10),
),
),
],
);
}
_infoText() {
return Expanded(
child: Container(
padding: EdgeInsets.only(top: 5, left: 8, right: 8, bottom: 5),
child: Column(
//从头开始显示
crossAxisAlignment: CrossAxisAlignment.start,
//上下显示
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//文字超多两行省略号
Text(
widget.homePageBean.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12, color: Colors.black87),
),
_owner(),
],
),
));
}
_owner() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Padding(
padding: EdgeInsets.only(right: 8),
child: Text(
"up",
style: TextStyle(fontSize: 10, color: Colors.grey),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Text(
widget.homePageBean.up,
style: TextStyle(fontSize: 10, color: Colors.grey),
),
),
],
),
Icon(
Icons.more_vert_sharp,
size: 15,
color: Colors.grey,
)
],
);
}
}
视频播放器
这个是在别人基础上改了下,然后直接使用的,具体看一下的的封装使用:
video_card.dart 代码:
import 'dart:async';
import 'dart:math';
import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_blbl/utils/color.dart';
import 'package:flutter_blbl/utils/toast.dart';
import 'package:screen_brightness/screen_brightness.dart';
import 'package:volume_controller/volume_controller.dart';
import 'fijk_controller.dart';
class CustomFijkPanel extends StatefulWidget {
final FijkPlayer player;
final BuildContext buildContext;
final Size viewSize;
final Rect texturePos;
final String videoTitle;
final bool isNextNumber;
final bool isPlayAd;
final void Function() onPlayAd;
final void Function() onBack;
final void Function() onError;
final void Function() onVideoEnd;
final void Function() onVideoPrepared;
final void Function() onVideoTimeChange;
/// 播放器控制器具体到源代码目录查看参考fijkplayer\lib\ui\panel.dart
/// ```
/// @param {FijkPlayer} player -
/// @param {BuildContext} buildContext -
/// @param {Size} viewSize -
/// @param {Rect} texturePos -
/// @param {String} videoTitle -
/// @param {bool} isNextNumber - 全屏后是否显示下一集按钮
/// @param {bool} isPlayAd - 是否显示广告按钮
/// @param {void Function()?} onPlayAd - 播放广告
/// @param {void Function()?} onBack - 返回按钮
/// @param {void Function()?} onError - 视频错误点击刷新
/// @param {void Function()?} onVideoEnd - 视频结束
/// @param {void Function()?} onVideoPrepared - 视频完成后台任务到稳定期
/// @param {void Function()?} onVideoTimeChange - 视频时间更新
/// ```
const CustomFijkPanel({
@required this.player,
@required this.buildContext,
@required this.viewSize,
@required this.texturePos,
@required this.videoTitle,
this.isNextNumber = false,
this.isPlayAd = false,
this.onPlayAd,
this.onBack,
this.onError,
this.onVideoEnd,
this.onVideoPrepared,
this.onVideoTimeChange,
});
@override
State<StatefulWidget> createState() {
return _CustomFijkPanelState();
}
}
class _CustomFijkPanelState extends State<CustomFijkPanel> {
FijkPlayer get player => widget.player;
bool get isFullScreen => player.value.fullScreen;
/// 总时间
Duration _duration = Duration();
/// 动画时间
Duration get _animatedTime => Duration(milliseconds: 400);
/// 是否在播放
bool _playing = false;
/// 后台任务是否初步执行完成是用于正在加载中的状态
bool _prepared = false;
/// 视频状态是否执行完成成为稳定状态与_prepared不一致
bool _playStatePrepared = false;
bool _isPlayCompleted = false;
/// 是否在加载中
bool _buffering = false;
int _bufferingPro = 0;
StreamSubscription _bufferingSubs;
/// 拖动快进的时间 -1不显示
double _seekPos