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内存模型JMM心得

    2023-11-28 20:56:17
  • Spring Boot修改内置Tomcat默认端口号的示例

    2023-03-29 21:11:40
  • C#使用Tesseract进行Ocr识别的方法实现

    2022-12-15 06:54:23
  • C#中方法的详细介绍

    2023-08-06 12:31:21
  • java安全编码指南之:Mutability可变性详解

    2023-11-11 06:30:24
  • Java Web实现文件下载和乱码处理方法

    2022-03-14 20:28:38
  • java基础之String知识总结

    2022-09-24 16:25:20
  • c# 预处理识别硬币的数据集

    2022-05-21 17:26:09
  • Java文件操作实例详解

    2023-11-25 10:29:40
  • Spring中ApplicationContextAware的使用方法详解

    2023-12-25 07:01:33
  • Java Swing JList列表框的实现

    2021-09-05 08:20:56
  • java实现九宫格拼图游戏

    2023-05-28 09:26:07
  • struts1之简单mvc示例_动力节点Java学院整理

    2021-10-28 14:43:03
  • 一文快速掌握Spring Cloud Stream

    2023-09-01 23:09:38
  • Android开发使用Drawable绘制圆角与圆形图案功能示例

    2023-08-26 21:07:09
  • c# 用Base64实现文件上传

    2023-12-20 00:52:11
  • Java Collection集合iterator方法解析

    2022-11-17 06:43:29
  • Android读取assets目录下的所有图片并显示的方法

    2023-03-09 22:06:30
  • 浅谈BeanPostProcessor加载次序及其对Bean造成的影响分析

    2022-05-02 19:52:29
  • SpringBoot整合RedisTemplate实现缓存信息监控的步骤

    2023-10-14 10:17:13
  • asp之家 软件编程 m.aspxhome.com