抽离弹幕组件提供的功能
ibarrage.dart
abstract class IBarrage {
// 发送弹幕
void send(String message);
// 暂停弹幕
void pause();
// 播放弹幕
void play();
}
封装弹幕Widget
barrage_item.dart
class BarrageItem extends StatelessWidget {
final String id;
final double top;
final Widget child;
final ValueChanged onComplete;
final Duration duration;
const BarrageItem(
{Key key, this.id, this.top, this.child, this.onComplete, this.duration})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}
弹幕组件核心类
hi_barrage.dart
实现弹幕播放控制相关
/// 弹幕播放状态
enum BarrageStatus { play, pause }
/// 弹幕组件核心类
class HiBarrage extends StatefulWidget {
// 弹幕行数
final int lineCount;
// 视频标识
final String vid;
// 弹幕速度
final int speed;
// 弹幕距离屏幕顶部的距离
final int top;
// 是否自动播放
final bool autoPlay;
const HiBarrage(
{Key key,
this.lineCount = 4,
@required this.vid,
this.speed = 800,
this.top = 0,
this.autoPlay = false})
: super(key: key);
@override
HiBarrageState createState() => HiBarrageState();
}
class HiBarrageState extends State<HiBarrage> implements IBarrage {
HiSocket _hiSocket;
double _height;
double _width;
// 弹幕Widget集合
final List<BarrageItem> _barrageItemList = [];
// 弹幕模型
final List<BarrageModel> _barrageModelList = [];
// 第几条弹幕
final int _barrageIndex = 0;
final Random _random = Random();
// 弹幕播放状态
BarrageStatus _barrageStatus;
// 定时器
Timer _timer;
@override
void initState() {
super.initState();
// 开启和服务端socket通信
_hiSocket = HiSocket(HiConstants.headers());
// 接收服务端返回的数据
_hiSocket.open(widget.vid).listen((value) {
_handleMessage(value);
});
}
/// 做一些资源释放
@override
void dispose() {
if (_hiSocket != null) {
_hiSocket.close();
}
if (_timer != null) {
_timer.cancel();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
_width = MediaQuery.of(context).size.width;
_height = _width / 16 * 9;
return SizedBox(
width: _width,
height: _height,
// 添加弹幕集合
child: Stack(
children: [
// 防止Stack的child为空
Container()
]..addAll(_barrageItemList),
),
);
}
/// 处理消息, instant = true 立马发送
void _handleMessage(List<BarrageModel> value, {bool instant = false}) {
if (instant) {
// 插入到对头
_barrageModelList.insertAll(0, value);
} else {
// 插入到末尾
_barrageModelList.addAll(value);
}
// 收到新的弹幕后播放
if (_barrageStatus == BarrageStatus.play) {
play();
return;
}
// 收到新的弹幕后播放
if (widget.autoPlay && _barrageStatus != BarrageStatus.pause) {
play();
return;
}
}
/// 播放弹幕
@override
void play() {
// 重置弹幕状态
_barrageStatus = BarrageStatus.play;
// 定时任务正在执行直接返回
if (_timer != null && _timer.isActive) return;
// 定时任务
_timer = Timer.periodic(Duration(milliseconds: widget.speed), (timer) {
if (_barrageModelList.isNotEmpty) {
// 取出第一个弹幕消息进行播放,并将此弹幕从集合中移除(防止重复播放)
var temp = _barrageModelList.removeAt(0);
// 添加弹幕消息
addBarrage(temp);
print('start:${temp.content}');
} else {
print('all barrage are sent.');
// 关闭定时器
_timer.cancel();
}
});
}
void addBarrage(BarrageModel temp) {}
/// 弹幕暂停
@override
void pause() {
// 重置播放状态
_barrageStatus = BarrageStatus.pause;
// 清空弹幕
_barrageItemList.clear();
// 刷新界面
setState(() {});
print('action:pause');
// 关闭定时器
_timer.cancel();
}
/// 发送弹幕
@override
void send(String message) {
if (message == null) return;
// 发送弹幕
_hiSocket.send(message);
// 添加弹幕实体到集合中
_barrageModelList
.add(BarrageModel(content: message, vid: '-1', priority: 1, type: 1));
}
}
添加弹幕组件到视频播放页
video_view.dart
视频播放Widget,添加弹幕组件Widget
class VideoView extends StatefulWidget {
...
final Widget barrageUI; // 弹幕UI
@override
void initState() {
super.initState();
_chewieController = ChewieController(
...
customControls: MaterialControls(
...
overlayUI: widget.overlayUI,
));
// 视屏状态发生变更时回调
_chewieController.addListener(_fullScreenListener);
}
video_detail_page.dart
视频播放详情页,传递弹幕Widget
// 创建弹幕的key,防止弹幕重复
var _barrageKey = GlobalKey<HiBarrageState>();
_videoView() {
var model = videoModel;
return VideoView(
model.url,
cover: model.cover,
overlayUI: videoAppBar(),
// 弹幕组件
barrageUI: HiBarrage(key: _barrageKey, vid: model.vid, autoPlay: true),
);
}