Android Flutter實現(xiàn)彈幕效果
前言
需求要點如下:
- 彈幕行數(shù)為3行,每條彈幕相互依靠但不存在重疊
- 每條彈幕可交互點擊跳轉(zhuǎn)
- 滾動速度恒定 觸摸不可暫停播放
- 彈幕數(shù)據(jù)固定一百條且支持輪詢播放
彈幕排序規(guī)則如下:
1 4 7
2 5 8
3 6 9
通用彈幕實現(xiàn)方案

Flutter Dev Package已有開源彈幕實現(xiàn)組件,這里舉例barrage_page的實現(xiàn)方式(大多數(shù)實現(xiàn)底層邏輯基本一樣)。
基本架構(gòu)采用Stack然后向布局中提交彈幕布局,添加時設(shè)置好彈幕偏移量來設(shè)置彈幕位置。
Stack(fit: StackFit.expand, children: <Widget>[
widget.child,
_controller.isEnabled
? Stack(
fit: StackFit.loose,
children: <Widget>[]
..addAll(_widgets.values ?? const SizedBox()))
: const SizedBox(),
]);
});
但因為每條彈幕可能會出現(xiàn)重疊情況無法合理定位每條彈幕的位置因此放棄該方案。
PS:widget只有在build到布局后才能獲取到它基礎(chǔ)信息(相對位置信息,寬高等)就無法計算出所有彈幕的位置信息。
ListView彈幕方案實現(xiàn)
最先想到使用瀑布流flutter_staggered_grid_view實現(xiàn)彈幕布局但由于組件暫時不支持橫向布局就放棄了。
基本框架
采用三個ListView實現(xiàn)每一行彈幕效果。雖然不太推薦以這種形式實現(xiàn)但從快速實現(xiàn)效果來說是比較簡單便捷兜底方案。(可以實現(xiàn)但不推薦)
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定時每秒鐘執(zhí)行一次scrollController的animateTo方法移動偏移量并且偏移量不斷累加。
其次ListView支持無限滑動只要ListView.builder不設(shè)置itemCount就能實現(xiàn)。
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回調(diào)下標Index會超出數(shù)據(jù)源最大值。因此數(shù)據(jù)源也需要支持無限輪詢來配合列表滾動。start表示彈幕開始取值,這里設(shè)置為(0,1,2);index表示itemBuilder回調(diào)下標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) { // 是否是最后一個數(shù)據(jù)
index = start;
if (index >= expressList.length) { // 還需要判斷數(shù)據(jù)源是否比start還小
index = (index % expressList.length - 1);
}
}
return index;
}
點擊事件
一切都實現(xiàn)得很順利最終就是彈幕點擊實現(xiàn)。但實際上當ListView的scrollController在執(zhí)行animateTo時其實點擊操作是失效的,ListView無法響應(yīng)點擊事件。只有當animateTo操作結(jié)束之后再執(zhí)行點擊才能執(zhí)行點擊。因此若要實現(xiàn)這個功能只能先將Timer暫停再執(zhí)行一次點擊,再一次點擊不可能是用戶再去觸發(fā),這里只能采用模擬點擊形式實現(xiàn)。
PS:ListView無法響應(yīng)點擊事件具體原因還待研究,個人猜測列表做動畫時對外部觸摸事件進行了屏蔽處理。
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: () {
// 內(nèi)部響應(yīng)點擊事件 然后重新設(shè)置定時器滾動列表
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
scroll();
});
},
);
},
),
);

到此這篇關(guān)于Android Flutter實現(xiàn)彈幕效果的文章就介紹到這了,更多相關(guān)Flutter彈幕效果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 詳解ThreadLocal及InheritableThreadLocal
這篇文章主要介紹了Android 詳解ThreadLocal及InheritableThreadLocal的相關(guān)資料,需要的朋友可以參考下2017-01-01
Android實現(xiàn)光點模糊漸變的自旋轉(zhuǎn)圓環(huán)特效
這篇文章主要為大家詳細介紹了Android實現(xiàn)光點模糊漸變的自旋轉(zhuǎn)圓環(huán)特效,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
比較完整的android MP3 LRC歌詞滾動高亮顯示(附源碼)
比較完整的android MP3 LRC歌詞滾動高亮顯示(附源碼)。需要的朋友可以過來參考下,希望對大家有所幫助2013-11-11
Android使用recyclerview打造真正的下拉刷新上拉加載效果
這篇文章先介紹如何使用這個recyclerview,WZMRecyclerview 是一個集成了 下拉刷新、上拉加載、滑到底部自動加載、添加刪除頭尾部 四個主要功能的recyclerview,需要的朋友可以參考下2016-11-11
Android將應(yīng)用調(diào)試log信息保存在SD卡的方法
Android將應(yīng)用調(diào)試log信息保存在SD卡的方法大家都知道嗎,下面腳本之家小編給大家分享Android將應(yīng)用調(diào)試log信息保存在SD卡的方法,感興趣的朋友參考下2016-04-04

