【问题标题】:RefreshIndicator with NestedScrollview带有 NestedScrollview 的 RefreshIndicator
【发布时间】:2018-09-10 19:26:47
【问题描述】:

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

但这带来了一个不同的问题,我还想要一个浮动的 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')
                    );
                }),
            )
        );
    }
}

AutomaticKeepAliveClientMixin 可以防止每次我切换标签页时重新构建页面,因为这在我的实际应用中会是一个昂贵的过程。

对两个选项卡使用单个 RefreshIndicator 的解决方案是最理想的,但我们不胜感激。

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    这段代码对我有用,它主要建立在@Nuts 答案之上,但它需要一些调整,我的编辑被拒绝了

    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,
              ),
            ),
          ),
        )
    

    【讨论】:

      【解决方案2】:

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

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

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

      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),
          ),
        ),
      

      添加一个调用未来的函数。在以后的部分中,如果标签栏视图的一个子或两个子视图将被滚动,我们将编写代码。

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

      }

      【讨论】:

        【解决方案3】:

        可以用 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,
                      ),
                    ),
                  ),
                )
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-04-26
          • 1970-01-01
          • 1970-01-01
          • 2018-04-11
          • 2017-02-03
          相关资源
          最近更新 更多