import 'package:flutter/material.dart';
class BidirectionalListPage extends StatefulWidget {
const BidirectionalListPage({super.key});
@override
State<BidirectionalListPage> createState() => _BidirectionalListPageState();
}
class _BidirectionalListPageState extends State<BidirectionalListPage> {
final ScrollController _controller = ScrollController();
final List<int> _items = List.generate(20, (i) => i); // 初始數(shù)據(jù)
bool _isLoadingUp = false;
bool _isLoadingDown = false;
@override
void initState() {
super.initState();
_controller.addListener(_onScroll);
}
void _onScroll() {
const threshold = 100.0; // 離邊界多少像素觸發(fā)
// 向上加載(歷史數(shù)據(jù))
if (_controller.position.pixels <=
_controller.position.minScrollExtent + threshold) {
_loadMoreUp();
}
// 向下加載(未來(lái)數(shù)據(jù))
if (_controller.position.pixels >=
_controller.position.maxScrollExtent - threshold) {
_loadMoreDown();
}
}
Future<void> _loadMoreUp() async {
if (_isLoadingUp) return; // 已經(jīng)在加載,避免重復(fù)觸發(fā)
setState(() => _isLoadingUp = true);
await Future.delayed(const Duration(seconds: 1)); // 模擬網(wǎng)絡(luò)請(qǐng)求
final first = _items.first;
final newItems = List.generate(10, (i) => first - (i + 1));
setState(() {
_items.insertAll(0, newItems.reversed.toList());
_isLoadingUp = false;
});
// 保持加載后視圖位置不跳動(dòng)
_controller.jumpTo(_controller.offset + 60 * newItems.length);
}
Future<void> _loadMoreDown() async {
if (_isLoadingDown) return;
setState(() => _isLoadingDown = true);
await Future.delayed(const Duration(seconds: 1));
final last = _items.last;
final newItems = List.generate(10, (i) => last + (i + 1));
setState(() {
_items.addAll(newItems);
_isLoadingDown = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("雙向加載 ListView")),
body: ListView.builder(
controller: _controller,
itemCount: _items.length,
itemBuilder: (context, index) {
return ListTile(
title: Center(child: Text("Index: ${_items[index]}")),
);
},
),
);
}
}
NotificationListener:onNotification()
bool notificationChange(Notification notification) {
if (notification is UserScrollNotification) {
if (notification.direction == ScrollDirection.forward) {
// 用戶手指向下滑動(dòng)(內(nèi)容往上滾)
debugPrint('?? 用戶向下滑動(dòng)了');
userScrolledUp = true;
} else if (notification.direction == ScrollDirection.reverse) {
// 用戶手指向上滑動(dòng)(內(nèi)容往下滾)
debugPrint('?? 用戶向上滑動(dòng)了');
// logic.userScrolledUp = false;
} else if (notification.direction == ScrollDirection.idle) {
debugPrint('?? 用戶滑動(dòng)結(jié)束了');
// 頂部觸發(fā)
if (scrollController.position.pixels <=
scrollController.position.minScrollExtent + threshold) {
Logger.safePrint('====》開(kāi)始拉取');
loadMoreUp();
}
// 底部觸發(fā)
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - threshold) {
loadMoreDown();
}
}
}
return false; // 返回 false 允許繼續(xù)向上傳遞通知
}
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。