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,

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

              ///結(jié)束加載更多,傳是否有新數(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:

下載源碼后,跳轉(zhuǎn)到下圖指向的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,

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

                ///結(jié)束加載更多栓霜,傳是否有新數(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();
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市横蜒,隨后出現(xiàn)的幾起案子胳蛮,更是在濱河造成了極大的恐慌销凑,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仅炊,死亡現(xiàn)場(chǎng)離奇詭異斗幼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抚垄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門蜕窿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人呆馁,你說我怎么就攤上這事桐经。” “怎么了智哀?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵次询,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我瓷叫,道長(zhǎng)屯吊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任摹菠,我火速辦了婚禮盒卸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘次氨。我一直安慰自己蔽介,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布煮寡。 她就那樣靜靜地躺著虹蓄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幸撕。 梳的紋絲不亂的頭發(fā)上薇组,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天,我揣著相機(jī)與錄音坐儿,去河邊找鬼律胀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛貌矿,可吹牛的內(nèi)容都是我干的炭菌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼逛漫,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼黑低!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起尽楔,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤投储,失蹤者是張志新(化名)和其女友劉穎第练,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玛荞,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娇掏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勋眯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婴梧。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖客蹋,靈堂內(nèi)的尸體忽然破棺而出塞蹭,到底是詐尸還是另有隱情,我是刑警寧澤讶坯,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布番电,位于F島的核電站,受9級(jí)特大地震影響辆琅,放射性物質(zhì)發(fā)生泄漏漱办。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一婉烟、第九天 我趴在偏房一處隱蔽的房頂上張望娩井。 院中可真熱鬧,春花似錦似袁、人聲如沸洞辣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扬霜。三九已至,卻和暖如春而涉,著一層夾襖步出監(jiān)牢的瞬間畜挥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工婴谱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人躯泰。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓谭羔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親麦向。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瘟裸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353