聊天雙向加載列表

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ù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容