带有 NestedScrollview 的 RefreshIndicator

Ste*_*her 8 dart flutter

我想要 2 个带有 ListView 的标签页,每个标签页共享一个 RefreshIndicator。但是,RefreshIndicator 必须将 Scrollable 作为子项(TabBarView 不是),因此我尝试为每个选项卡制作 2 个 RefreshIndicators,如下面的代码所示。

但这带来了一个不同的问题,我还想要一个浮动的 AppBar,这意味着我必须使用 NestedScrollView。因此,每当我向下滚动时,我最终都会触发两个 RefreshIndicators 的 onRefresh 方法。而我只需要一个来刷新。

import 'package:flutter/material.dart';

main() {
    runApp(
        MaterialApp(
            home: DefaultTabController(
                length: 2,
                child: Scaffold(
                    body: NestedScrollView(
                        headerSliverBuilder: (context, innerBoxIsScrolled) {
                            return [
                                SliverAppBar(
                                    floating: true,
                                    snap: true,
                                    bottom: TabBar(
                                        tabs: [
                                            Tab(text: 'Page1'),
                                            Tab(text: 'Page2'),
                                        ],
                                    ),
                                ),
                            ];
                        },
                        body: TabBarView(
                            children: [
                                Page(1),
                                Page(2),
                            ],
                        ),
                    ),
                ),
            ),
        ),
    );
}

class Page extends StatefulWidget {
    final pageNumber;
    Page(this.pageNumber);
    createState() => PageState();
}

class PageState extends State<Page> with AutomaticKeepAliveClientMixin {
    get wantKeepAlive => true;

    build(context){
        super.build(context);
        return RefreshIndicator(
            onRefresh: () => Future(() async {
                print('Refreshing page no. ${widget.pageNumber}');  // This prints twice once both tabs have been opened
                await Future.delayed(Duration(seconds: 5));
            }),
            child: ListView.builder(
                itemBuilder: ((context, index){
                    return ListTile(
                        title: Text('Item $index')
                    );
                }),
            )
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

AutomaticKeepAliveClientMixin 用于防止每次切换选项卡时重新构建页面,因为这在我的实际应用程序中将是一个昂贵的过程。

对两个选项卡使用单个 RefreshIndicator 的解决方案将是最理想的,但感谢任何帮助。

Bas*_*ous 24

    DefaultTabController(
      length: tabs.length,
      child: RefreshIndicator(
        notificationPredicate: (notification) {
          // with NestedScrollView local(depth == 2) OverscrollNotification are not sent
          return notification.depth == 2;
        },
        onRefresh: () => Future.value(null),
        child: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              SliverAppBar(...)
            ];
          },
          body: TabBarView(
            children: tabs,
          ),
        ),
      ),
    )
Run Code Online (Sandbox Code Playgroud)


Nut*_*uts 10

可以用 RefreshIndicator 包装整个 NestedScrollView 并更新 notificationPredicate:

       DefaultTabController(
          length: tabs.length,
          child: RefreshIndicator(
            notificationPredicate: (notification) {
              // with NestedScrollView local(depth == 2) OverscrollNotification are not sent
              if (notification is OverscrollNotification || Platform.isIOS) {
                return notification.depth == 2;
              }
              return notification.depth == 0;
            },
            onRefresh: () => Future.value(null),
            child: NestedScrollView(
              headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
                return [
                  SliverAppBar(...)
                ];
              },
              body: TabBarView(
                children: tabs,
              ),
            ),
          ),
        )
Run Code Online (Sandbox Code Playgroud)


小智 1

如果您想要浮动应用程序栏,那么您必须使用嵌套滚动视图和 sliver app bar 。当您尝试在选项卡栏视图的子级列表中使用刷新指示器时,刷新指示器不起作用。这只是因为嵌套滚动视图。

如果您假设有两个列表作为选项卡栏视图的子项,则您希望一次仅刷新一个或两个列表,然后按照以下代码进行操作。

用刷新指示器包裹嵌套滚动视图,然后在刷新部分,

RefreshIndicator(
    color: Colors.red,
    displacement: 70,


    onRefresh: _refreshGeneralList,
    key: _refreshIndicatorKey,
    child: NestedScrollView(


      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
        return <Widget>[

          SliverAppBar(

            centerTitle: true,
            title: Text(
              "App Bar",
              style: TextStyle(
                  color: Colors.black,
                  fontSize: 14,
            ),
            leading: Padding(
              padding: const EdgeInsets.only(left: 8.0),
              child: IconButton(
                icon: Icon(Icons.profile),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ),
            actions: [
              InkWell(
                  onTap: () {
                    setState(() {
                      isPremium = !isPremium;
                    });
                  },
                  child: Icon(
                    Icons.monetization_on,
                    color: isPremium ? Colors.green : Colors.blueGrey,
                    size: 33,
                  )),
              SizedBox(
                width: 25,
              )
            ],

            elevation: 0,
            backgroundColor: Colors.white,
            pinned: true,
            floating: true,
            forceElevated: innerBoxIsScrolled,
            bottom: isPremium
                ? TabBar(

                labelStyle: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w600),
                labelColor: Colors.blueGrey,
                indicatorColor:Colors.red,
                unselectedLabelColor:
                Colors.green,
                labelPadding: EdgeInsets.symmetric(vertical: 13.5),
                controller: _tabController,
                tabs: [
                  Text(
                    "General",
                  ),
                  Text(
                    "Visitors",
                  ),
                ])
                : null,
          )
        ];
      },

      body: isPremium
          ? TabBarView(

          controller: _tabController,
          children: [
        generalNotificationsList(context),
        visitorsNotificationsList(context),
      ])
          : generalNotificationsList(context),
    ),
  ),
Run Code Online (Sandbox Code Playgroud)

添加一个调用 future 的函数。在后面的部分中,我们将编写标签栏视图的一个或两个子视图是否滚动的代码。

 Future _refreshGeneralList() async{
print('refreshing ');
GeneralNotificationBloc().add(LoadGeneralNotificationEvent(context));
PremiumNotificationBloc().add(LoadPremiumNotificationEvent(context));
return Future.delayed(Duration(seconds: 1));
Run Code Online (Sandbox Code Playgroud)

}