Android Flutter实现弹幕效果

 更新时间:2022年06月18日 09:33:07   作者:JulyYu  
这篇文章主要为大家详细介绍如何利用Android FLutter实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言

需求要点如下:

  • 弹幕行数为3行,每条弹幕相互依靠但不存在重叠
  • 每条弹幕可交互点击跳转
  • 滚动速度恒定 触摸不可暂停播放
  • 弹幕数据固定一百条且支持轮询播放

弹幕排序规则如下:

1 4 7

2 5 8

3 6 9

通用弹幕实现方案

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实现弹幕效果的文章就介绍到这了,更多相关Flutter弹幕效果内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android进阶之从IO到NIO的模型机制演进

    Android进阶之从IO到NIO的模型机制演进

    这篇文章主要为大家介绍了Android进阶之从IO到NIO的模型机制演进详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • 基于AnDroid FrameLayout的使用详解

    基于AnDroid FrameLayout的使用详解

    本篇文章是对AnDroid FrameLayout的使用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Android 侧滑按钮的实现代码

    Android 侧滑按钮的实现代码

    这篇文章主要介绍了Android 侧滑按钮的实现,本文结合示例代码图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • Android仿eleme点餐页面二级联动列表

    Android仿eleme点餐页面二级联动列表

    本站一直在点外卖,于是心血来潮就像仿饿了么做个站,接下来通过本文给大家介绍android 二级联动列表,仿eleme点餐页面的相关资料,需要的朋友可以参考下
    2016-10-10
  • Android项目中使用HTTPS配置的步骤详解

    Android项目中使用HTTPS配置的步骤详解

    这篇文章主要给大家介绍了关于Android项目中使用HTTPS配置步骤的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-06-06
  • Flutter DateTime日期转换的详细使用

    Flutter DateTime日期转换的详细使用

    本文主要介绍了Flutter DateTime日期转换的详细使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Android微信自动抢红包插件优化和实现

    Android微信自动抢红包插件优化和实现

    这篇文章主要为大家详细介绍了Android微信自动抢红包插件优化和实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • Android PickerView实现三级联动效果

    Android PickerView实现三级联动效果

    这篇文章主要为大家详细介绍了Android PickerView实现三级联动效果,PickerView实现全国地址的选择,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • Android数据存储几种方式讲解

    Android数据存储几种方式讲解

    在开发过程中,数据存取是较为频繁的,今天我们来了解下android几种常见的数据存取方式。在Android中,sharePreferences是一种轻量级的数据存储方式,采用键值对的存储方式,存储少量数据,支持基本类型的简单数据存储
    2022-12-12
  • android9.0 默认apk权限添加方法

    android9.0 默认apk权限添加方法

    本文给大家分享android9.0 默认apk权限添加方法,默认赋予全部权限,根据包名赋予权限,通过default-permissions-google.xml的方式实现,文中通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2021-06-06

最新评论