长弹幕会出现换行情况

来源: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回答

CrazyCodeBoy

2022-07-15

可以尝试给弹幕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,
        ));
  }
1
1
慕妹8246037
很棒,好使
2022-07-15
共1条回复

慕妹8246037

提问者

2022-07-14

看样子是:一个弹幕结束之后,弹幕容器setState移除这条弹幕 影响了其他弹幕的动画状态,怎么解决?

0
0

Flutter高级进阶实战-仿哔哩哔哩-掌握Flutter高阶技能

一次性掌握Flutter高阶技能+商业级复杂项目架构设计与开发方案

1723 学习 · 870 问题

查看课程