Android Flutter实现弹幕效果

作者:JulyYu 时间:2022-07-17 16:15:17 

前言

需求要点如下:

  • 弹幕行数为3行,每条弹幕相互依靠但不存在重叠

  • 每条弹幕可交互点击跳转

  • 滚动速度恒定 触摸不可暂停播放

  • 弹幕数据固定一百条且支持轮询播放

弹幕排序规则如下:

1 4 7

2 5 8

3 6 9

通用弹幕实现方案

Android Flutter实现弹幕效果

Flutter Dev Package已有开源弹幕实现组件,这里举例barrage_page的实现方式(大多数实现底层逻辑基本一样)。

基本架构采用Stack然后向布局中提交弹幕布局,添加时设置好弹幕偏移量来设置弹幕位置。

Stack(fit: StackFit.expand, children: <Widget>[
       widget.child,
       _controller.isEnabled
           ? Stack(
           fit: StackFit.loose,
           children: <Widget>[]
             ..addAll(_widgets.values ?? const SizedBox()))
           : const SizedBox(),
     ]);
   });

弹幕效果代码

但因为每条弹幕可能会出现重叠情况无法合理定位每条弹幕的位置因此放弃该方案。

PS:widget只有在build到布局后才能获取到它基础信息(相对位置信息,宽高等)就无法计算出所有弹幕的位置信息。

ListView弹幕方案实现

最先想到使用瀑布流flutter_staggered_grid_view实现弹幕布局但由于组件暂时不支持横向布局就放弃了。

基本框架

采用三个ListView实现每一行弹幕效果。虽然不太推荐以这种形式实现但从快速实现效果来说是比较简单便捷兜底方案。(可以实现但不推荐)

Container(
 height: 200,
 child: Column(
   children: [
     Expanded(
       child: ListView.builder(
         scrollDirection: Axis.horizontal,
         controller: scrollController1,
         itemBuilder: (context, index) {
           return Common.getWidget(index,
               height: 30, width: random.nextInt(100).toDouble());
         },
       ),
     ),
     Expanded(
         child: ListView.builder(
       scrollDirection: Axis.horizontal,
       controller: scrollController2,
       itemBuilder: (context, index) {
         return Common.getWidget(index,
             height: 30, width: random.nextInt(100).toDouble());
       },
     )),
     Expanded(
         child: ListView.builder(
       scrollDirection: Axis.horizontal,
       controller: scrollController3,
       itemBuilder: (context, index) {
         return Common.getWidget(index,
             height: 30, width: random.nextInt(100).toDouble());
       },
     ))
   ],
 ),
)

轮播滚动

添加定时器periodic定时每秒钟执行一次scrollControlleranimateTo方法移动偏移量并且偏移量不断累加。

其次ListView支持无限滑动只要ListView.builder不设置itemCount就能实现。

Timer _timer;

scroll = () {
 offset += 100;
 scrollController1.animateTo(offset,
     duration: Duration(seconds: 1), curve: Curves.linear);
 scrollController2.animateTo(offset,
     duration: Duration(seconds: 1), curve: Curves.linear);
 scrollController3.animateTo(offset,
     duration: Duration(seconds: 1), curve: Curves.linear);
};
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
 scroll();
});

轮询算法

ListView支持无限滑动后itemBuilder回调下标Index会超出数据源最大值。因此数据源也需要支持无限轮询来配合列表滚动。start表示弹幕开始取值,这里设置为(0,1,2);index表示itemBuilder回调下标Index

int findIndex(int start, int index) {
 index = start + index * 3;
 if (expressList.length < index) {
   index = index % (expressList.length - 1); // 取余
 } else if (expressList.length == index) { // 是否是最后一个数据
   index = start;
   if (index >= expressList.length) { // 还需要判断数据源是否比start还小
     index = (index % expressList.length - 1);
   }
 }
 return index;
}

点击事件

一切都实现得很顺利最终就是弹幕点击实现。但实际上当ListViewscrollController在执行animateTo时其实点击操作是失效的,ListView无法响应点击事件。只有当animateTo操作结束之后再执行点击才能执行点击。因此若要实现这个功能只能先将Timer暂停再执行一次点击,再一次点击不可能是用户再去触发,这里只能采用模拟点击形式实现。

PS:ListView无法响应点击事件具体原因还待研究,个人猜测列表做动画时对外部触摸事件进行了屏蔽处理。

GestureDetector(
 onTapUp: (details){
  // 点击抬起之后暂停定时器
   _timer?.cancel();
   // 模拟一次点击
   Timer(Duration(milliseconds: 100),() {
     GestureBinding.instance.handlePointerEvent(PointerAddedEvent(pointer: 0,position: details.globalPosition));
     GestureBinding.instance.handlePointerEvent(PointerDownEvent(pointer: 0,position: details.globalPosition));
     GestureBinding.instance.handlePointerEvent(PointerUpEvent(pointer: 0,position: details.globalPosition));
   });
 },
 child: ListView.builder(
   controller: scrollController,
   physics: NeverScrollableScrollPhysics(),
   itemBuilder: (context, index) {
     return GestureDetector(
       behavior: HitTestBehavior.opaque,
       child: Common.getWidget(index),
       onTap: () {
         // 内部响应点击事件 然后重新设置定时器滚动列表
         _timer = Timer.periodic(Duration(seconds: 1), (timer) {
           scroll();
         });
       },
     );
   },
 ),
);

Android Flutter实现弹幕效果

来源:https://juejin.cn/post/7110108145292165150

标签:Android,Flutter,弹幕
0
投稿

猜你喜欢

  • 利用java实现单词倒序排列

    2023-07-01 04:30:51
  • java实现九宫格拼图游戏

    2023-05-28 09:26:07
  • Java获取时间打印到控制台代码实例

    2022-07-20 22:43:48
  • C#使用iTextSharp添加PDF水印

    2021-10-09 08:59:27
  • Java Integer如何获取第一位和最后一位,并截取

    2022-12-27 08:27:13
  • Spring RabbitMQ死信机制原理实例详解

    2022-04-29 18:52:18
  • 详解Android实现定时器的几种方法

    2021-10-17 17:37:17
  • Android中使用Toast.cancel()方法优化toast内容显示的解决方法

    2021-12-14 05:17:03
  • SpringBoot中使用Servlet三大组件的方法(Servlet、Filter、Listener)

    2021-07-19 18:41:43
  • IDEA JetBrains Mono字体介绍和安装教程(详解)

    2022-01-23 17:57:51
  • C# SkinEngine控件 给窗体添加皮肤的方法

    2021-10-21 23:32:08
  • 一篇文章带你搞定JAVA注解

    2023-03-15 05:22:23
  • Java Swing JCheckBox复选框的实现方法

    2023-03-18 17:14:10
  • C# wpf Grid中实现控件拖动调整大小的示例代码

    2023-05-15 17:12:03
  • 普通类注入不进spring bean的解决方法

    2021-06-07 19:22:41
  • java实现一次性压缩多个文件到zip中的方法示例

    2021-11-16 07:24:47
  • cascade级联关系操作案例详解

    2022-04-11 08:11:09
  • webuploader 实现图片批量上传功能附实例代码

    2022-12-03 09:13:34
  • C#中Invoke的用法讲解

    2023-10-26 03:24:36
  • javaweb实现在线支付功能

    2022-02-08 19:17:34
  • asp之家 软件编程 m.aspxhome.com