长弹幕会出现换行情况
来源:11-8 基于Animation实现视频弹幕动效

慕妹8246037
2022-07-14
运行老师的代码发现长弹幕会换行,但是基本上app弹幕是不会换行且裁断的
所以我试了一下,长弹幕从屏幕右侧,一直向左移动到-弹幕的宽度,
但是当有屏幕中有弹幕的动画完成的时候,setState 移除这条弹幕,影响了其他弹幕的动画状态,导致的现象是总有两条弹幕在UI上提前结束了动画,但是controller监听不到动画complete。
怎么解决
弹幕容器代码(简化了老师课程的业务逻辑,定时器轮训 弹幕列表,取第一条显示到屏幕中):
class _DanMuWidgetState extends State<DanMuWidget> {
late SocketClient _client;
int _shownDanMuCount = 0; // 一共显示的弹幕数量
final Duration _danMuFrequency = const Duration(milliseconds: 500);
final List<DanMuModel> _danMuList = []; // 接受到的弹幕
late Timer _timer;
final List<DanMuItemWidgetConfig> showingItems = []; // 屏幕中正在显示的弹幕
@override
initState() {
super.initState();
_timer = Timer.periodic(_danMuFrequency, handleDanMuTimer);
_client = SocketClient(widget.vid).connect()
..listen((messages) {
_danMuList.addAll(messages);
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: showingItems.map((e) => DanMuItemWidget(config: e,)).toList(),
);
}
handleDanMuTimer(Timer timer) {
if (_danMuList.isEmpty) {
return;
}
if (context.size == null || context.size!.height == 0) {
return;
}
var lineHeight = 30.0;
var lineCount = context.size!.height ~/ lineHeight;
var danMuModel = DanMuItemWidgetConfig(_shownDanMuCount,
(_shownDanMuCount % lineCount) * lineHeight, context.size!.width, _danMuList.first, (config) {
showingItems.removeWhere((element) => element.id == config.id);
setState(() {});
});
showingItems.add(danMuModel);
setState(() {});
_shownDanMuCount++;
_danMuList.removeAt(0);
}
}
弹幕单元代码
class _DanMuItemWidgetState extends State<DanMuItemWidget>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation _animation;
@override
initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 5));
var end = -(TextUtil.calculateTextWidth(widget.config.danMuModel.content, 14, FontWeight.normal) + 5); // -(文本宽度 + 5)
_animation = Tween(begin: widget.config.initialLeft, end: end).animate(_controller);
_controller.forward();
_controller.addStatusListener((status) {
print('${widget.config.danMuModel.content} $status');
if (status == AnimationStatus.completed) { // 会有弹幕监听不到这个状态
widget.config.onComplete?.call(widget.config);
}
});
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (ctx, child) {
return Positioned(
left: _animation.value,
top: widget.config.top,
child: child!,
);
},
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.white),
borderRadius: const BorderRadius.all(Radius.circular(3))),
child: Text(
widget.config.danMuModel.content,
style: const TextStyle(
color: Colors.white, fontSize: 14, fontWeight: FontWeight.normal),
),
),
);
}
@override
dispose() {
_controller.dispose();
super.dispose();
}
}
弹幕配置类
class DanMuItemWidgetConfig {
final int id;
final double top;
final double initialLeft; // 初始左边位置,也就是屏幕宽度
final DanMuModel danMuModel;
final ValueChanged<DanMuItemWidgetConfig>? onComplete;
DanMuItemWidgetConfig(this.id, this.top, this.initialLeft, this.danMuModel, this.onComplete);
}
写回答
2回答
-
可以尝试给弹幕widget设置个GlobalKey,可参考barrage_item.dart的实现:
//fix 动画状态错乱
var _key = GlobalKey<BarrageTransitionState>();
@override
Widget build(BuildContext context) {
return Positioned.fill(
top: top,
child: BarrageTransition(
key: _key,
child: child,
onComplete: (v) {
onComplete(id);
},
duration: duration,
));
}112022-07-15 -
慕妹8246037
提问者
2022-07-14
看样子是:一个弹幕结束之后,弹幕容器setState移除这条弹幕 影响了其他弹幕的动画状态,怎么解决?
00
相似问题