flutter 上拉加載更多下拉刷新通用widget,child可以是任何widget,支持自定義多種狀態(tài)顯示


更新:

XBRefresh

安裝

flutter pub add xb_refresh

使用

// ignore_for_file: library_private_types_in_public_api

import 'package:xb_scaffold/xb_scaffold.dart';
import 'xb_refresh.dart';

class XBRefreshDemo extends XBPage<XBRefreshDemoVM> {
  const XBRefreshDemo({super.key});

  @override
  generateVM(BuildContext context) {
    return XBRefreshDemoVM(context: context);
  }

  @override
  bool needShowContentFromScreenTop(XBRefreshDemoVM vm) {
    return true;
  }

  @override
  List<Widget>? actions(XBRefreshDemoVM vm) {
    return [
      XBButton(
          onTap: () {
            vm.xbRefreshController.refresh();
          },
          child: Container(
            color: Colors.transparent,
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text("開始刷新"),
            ),
          )),
    ];
  }

  @override
  Widget buildPage(vm, BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(top: topBarH),
      child: Container(
        height: screenH * 0.8,
        width: screenW * 0.8,
        color: colors.randColor,
        child: XBRefresh(
          controller: vm.xbRefreshController,
          needLoadMore: true,
          needRefresh: true,
          initRefresh: true,

          ///開始加載更多的回調
          onLoadMore: () {
            Future.delayed(const Duration(seconds: 2), () {
              bool hasMore = false;
              if (vm.itemCount < 20) {
                hasMore = true;
                vm.itemCount += 2;
                vm.notify();
              }

              ///結束加載更多,傳是否有新數(shù)據(jù)
              vm.xbRefreshController.endLoadMore(hasMore);
            });
          },
          onRefresh: () {
            Future.delayed(const Duration(seconds: 1), () {
              vm.itemCount = 10;
              vm.xbRefreshController.endRefresh();
              vm.notify();
            });
          },
          headerCompleteBuilder: (height) {
            return Container(
              height: height,
              color: Colors.red,
              child: const Center(
                child: Text("完成刷新"),
              ),
            );
          },
          footerHasMoreBuilder: (height) {
            return Container(
              height: height,
              color: Colors.green,
              child: const Center(
                child: Text("拉取新數(shù)據(jù)完成"),
              ),
            );
          },
          child: ListView.builder(
            itemCount: vm.itemCount,
            itemBuilder: (context, index) {
              return Cell("$index", () {});
            },
          ),
        ),
      ),
    );
  }
}

class XBRefreshDemoVM extends XBPageVM<XBRefreshDemo> {
  XBRefreshDemoVM({required super.context}) {
    controller.addListener(listenFun);
  }
  final ScrollController controller = ScrollController();
  final XBRefreshController xbRefreshController = XBRefreshController();

  int itemCount = 10;

  void listenFun() {
    xbError("controller.offset:${controller.offset}");
  }

  @override
  void dispose() {
    controller.removeListener(listenFun);
    controller.dispose();
    super.dispose();
  }
}

class Cell extends StatelessWidget {
  static const height = 44.0;
  final String title;
  final VoidCallback onPressed;

  const Cell(this.title, this.onPressed, {super.key});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onPressed,
      child: Container(
        height: height,
        color: Colors.black38,
        alignment: Alignment.center,
        child: Column(
          children: <Widget>[
            Expanded(
                child: Center(
                    child: Text(title,
                        style: const TextStyle(color: Colors.white)))),
            Container(
              height: 1,
              color: Colors.white,
            )
          ],
        ),
      ),
    );
  }
}


原文

1,通用性,child可以是任何widget

2,支持多種狀態(tài):

上拉加載更多:繼續(xù)上拉加載更多、松手開始加載、正在加載、加載到了新數(shù)據(jù)、沒有新數(shù)據(jù)
下拉刷新:繼續(xù)下拉刷新、松手開始刷新、正在刷新、刷新完成

3,支持自定義每種狀態(tài)的widget


源碼:

XBRefresh

效果:

XBRefreshGif.gif


思路:

下拉和上拉類似的,這里就說上拉。
借住Stack,底層是Column,上層是外部傳入的child。


image.png

流程圖(僅上拉):

上拉加載更多流程圖.jpg


demo:

下載源碼后,跳轉到下圖指向的page查看效果。


XBRefreshDemoJpg.png
class _XBRefreshDemoState extends State<XBRefreshDemo> {
  ScrollController _controller = ScrollController();
  GlobalKey<XBRefreshState> _refreshKey = GlobalKey();

  int _itemCount = 10;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller.addListener(() {
      _refreshKey.currentState.receiveOffset(
          _controller.offset, _controller.position.maxScrollExtent);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("xb refresh demo"),
        ),
        body: XBRefresh(
            key: _refreshKey,
            needLoadMore: true,
            needRefresh: true,

            ///開始加載更多的回調
            onBeginLoadMore: () {
              Future.delayed(Duration(seconds: 2), () {
                bool hasMore = false;
                if (_itemCount < 20) {
                  hasMore = true;
                  setState(() {
                    _itemCount += 5;
                  });
                }

                ///結束加載更多,傳是否有新數(shù)據(jù)
                _refreshKey.currentState.endLoadMore(hasMore);
              });
            },
            onBeginRefresh: () {
              Future.delayed(Duration(seconds: 1), () {
                setState(() {
                  _itemCount = 10;
                });
                _refreshKey.currentState.endRefresh();
              });
            },
            child: CustomScrollView(
              controller: _controller,
              physics: AlwaysScrollableScrollPhysics(
                  parent: BouncingScrollPhysics()),
              slivers: <Widget>[
                SliverList(
                    delegate: SliverChildBuilderDelegate((ctx, index) {
                  return Cell("$index", () {});
                }, childCount: _itemCount))
              ],
            )));
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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