【问题标题】:Refresh indicator without scrollview没有滚动视图的刷新指示器
【发布时间】:2018-10-16 03:23:49
【问题描述】:

我知道ListViewSingleChildScrollView RefreshIndicator 只能在本机工作,但我想在不滚动的页面上使用RefreshIndicator。这甚至可能吗?如果可以,怎么做?

【问题讨论】:

    标签: flutter


    【解决方案1】:

    您必须执行以下操作:

    • 使用SingleChildScrollView 并将属性physics 设置为AlwaysScrollableScrollPhysics()
    • 确保孩子的高度与屏幕大小一致,您可以通过MediaQuery.of(context).size.height 获得。

    完整的例子:

    classs MyWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return RefreshIndicator(
          onRefresh: () {},
          child: SingleChildScrollView(
            physics: AlwaysScrollableScrollPhysics(),
            child: Container(
              child: Center(
                child: Text('Hello World'),
              ),
              height: MediaQuery.of(context).size.height,
            ),
          ),
        );
      }
    }
    

    【讨论】:

    • 有点相关,我在小部件树的某处有一个 listview.builder,我只需要使用物理 AlwaysScrollableScrollPhysics() 和它上方容器中的媒体查询高度即可实现相同的目的。
    • 如果我想在不使用 ListView 的情况下滚动视图怎么办?PLZ 告诉!我有一个未来的构建器作为可滚动的刷新指示器的孩子
    【解决方案2】:

    所以在我的例子中,我想在一个空列表中显示一个占位符:

              RefreshIndicator(
                child: Stack(
                  children: <Widget>[
                    Center(
                      child: Text("The list is empty"),
                    ),
                    ListView()
                  ],
                ),
                onRefresh: () {},
              )
    

    【讨论】:

    • 这也是我使用的。但是对于需要用户点击按钮的列表视图上方的小部件,它不起作用。
    • @chitgoks 很抱歉没有找到你。您指的是哪些“按钮”?
    【解决方案3】:

    大多数其他答案都可以,但它们都有一些缺点:

    • 使用SingleChildScrollView而不调整高度会导致“滚动发光效果”不在页面底部。
    • 将高度设置为当前视图的最大高度(通过使用MediaQueryLayoutBuilder)将解决此问题,但是当您的内容高度大于可用高度时会出现渲染溢出空间。

    最后,以下解决方案非常适合我:

    LayoutBuilder(
      builder: (context, constraints) => RefreshIndicator(
        onRefresh: _refresh,
        child: SingleChildScrollView(
          physics: AlwaysScrollableScrollPhysics(),
          child: ConstrainedBox(
            constraints: BoxConstraints(
              minHeight: constraints.maxHeight
            ),
            child: Text("Your Widget")
          )
        )
      ),
    )
    

    【讨论】:

      【解决方案4】:

      建议将AlwaysScrollableScrollPhysics()RefreshIndicator 一起使用,因为如果Scrollable 可能没有足够的内容进行过度滚动,请考虑将其physics 属性设置为AlwaysScrollableScrollPhysics

      无需创建自己的子类,parent 可用于组合不同类型的 ScrollPhysics 对象以获得所需的滚动物理效果。例如:

      ListView(
        physics: const AlwaysScrollableScrollPhysics(),
        children: ...
      )
      

      注意RefreshIndicator 只能用于垂直滚动视图。

      【讨论】:

      • 你只复制别人的答案并作为你的发布吗?这是original answer,你没有做任何特别的事情。从现在开始,我会留意你的回答表格。
      • 是的,我知道,但我认为我没有抄袭,但我想了更多,然后我得到了相关的东西,然后我尝试解释那个解决方案。但是,如果您这么认为,那么我准备删除这样的答案。
      • 如果您有一些小问题要添加到答案中,请编辑他们的帖子并添加您的发言权。除非您指定一些警告,否则发布相同的答案没有任何好处。我希望你不介意。谢谢你,祝你有美好的一天!
      • 如果不知道它是如何工作的,我们就无法理解它,所以我研究它并获取信息,然后我给出了一些详细的答案。但现在我明白了你的意思,现在我会注意的,谢谢你对我的认识!
      • 我明白,但与其解释已经写好的答案,不如写一个独特的答案:)
      【解决方案5】:

      更灵活的解决方案是将可滚动的空/错误状态小部件放入 LayoutBuilder

      LayoutBuilder(
        builder: (context, constraints) => SingleChildScrollView(
          physics: AlwaysScrollableScrollPhysics(),
          child: SizedBox(
            height: constraints.maxHeight,
            child: ErrorState(
                subtitle: (snapshot.data as ErrorStateful).errorMessage),
          ),
        ),
      );
      

      【讨论】:

        【解决方案6】:

        是否可以没有不滚动的页面?

        -没有。


        请阅读 RefreshIndicator 中参数 child 的文档:

        树中此小部件下方的小部件。

        刷新指示器将堆叠在这个孩子的顶部。当孩子的 Scrollable 后代过度滚动时,该指示器将出现。

        通常是 [ListView] 或 [CustomScrollView]。


        有解决办法吗?

        -是的

        您只能在 Listview 的子列表中放置一个小部件:

        new RefreshIndicator(
          child: new ListView(
            children: <Widget>[
              new Text('This is child with refresh indicator'),
            ],
          ),
          onRefresh: () {},
        )
        

        【讨论】:

        • 这并不是真正的解决方法,这正是 OP 想要避免的。一种解决方法是添加一个拖动手势,该手势从顶部带来一个刷新指示器,如果释放是在拖动开始下方大约一些像素,那么,触发你想要的刷新方法。'
        【解决方案7】:

        ListView.builder 中使用 physics: AlwaysScrollableScrollPhysics()

        例子:

        RefreshIndicator(
           onRefresh: () => _onRefresh(),
           child: Center(
                    child: ListView.builder(
                             physics: AlwaysScrollableScrollPhysics(),
                              controller: _scrollController,
                              itemCount: 4,
                              addAutomaticKeepAlives: true,
                              itemBuilder: (BuildContext context, int position) {
                                    return Text("Hello $position");
                                  }
                      ),
              ),
        )
        

        【讨论】:

          【解决方案8】:

          其他答案中的SingleChildScrollView 解决方案适用于大多数情况。

          我有一个用例*,它不起作用,因为 SingleChildScrollView 中的内容想要扩展以填充剩余的高度。所以SingleChildScrollViewExpanded 小部件相互矛盾。

          最终,拯救了这一天的是使用 CustomScrollViewSliverFillRemaining 小部件。

          无需计算自定义小部件尺寸。

          代码:

          class DemoApp extends StatelessWidget {
            @override
            Widget build(BuildContext context) {
              return MaterialApp(
                home: Scaffold(
                  body: RefreshIndicator(
                    onRefresh: () async {
                      await Future.delayed(const Duration(seconds: 1));
                    },
                    child: CustomScrollView(
                      slivers: <Widget>[
                        SliverFillRemaining(
                          child: Container(
                            color: Colors.blue,
                            child: Center(
                              child: Text("No results found."),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              );
            }
          }
          

          您也可以在 DartPad 上进行测试。

          *我的用例:

          【讨论】:

            【解决方案9】:

            补充 Gustavo 答案,您可以使用约束以这种方式定义 SingleChildScrollView 的最小大小

            class MyWidget extends StatelessWidget {
              @override
              Widget build(BuildContext context) {
                return RefreshIndicator(
                  onRefresh: () {},
                  child: ConstrainedBox(
                    constraints: BoxConstraints(
                      minHeight: MediaQuery.of(context).size.height,
                    ),
                    child: SingleChildScrollView(
                      physics: AlwaysScrollableScrollPhysics(),
                      child: Center(
                        child: Text('Hello World'),
                      ),
                    ),
                  ),
                );
              }
            }
            

            【讨论】:

              【解决方案10】:

              这是你需要的完整代码(包括解决了使用appBar时的高度问题):

              import 'package:flutter/material.dart';
              
              class RefreshFullScreen extends StatefulWidget {
                const RefreshFullScreen({Key? key}) : super(key: key);
              
                @override
                _RefreshFullScreenState createState() => _RefreshFullScreenState();
              }
              
              class _RefreshFullScreenState extends State<RefreshFullScreen> {
                @override
                Widget build(BuildContext context) {
              
                  double height = MediaQuery.of(context).size.height; // Full screen width and height
                  EdgeInsets padding = MediaQuery.of(context).padding; // Height (without SafeArea)
                  double netHeight = height - padding.top - kToolbarHeight; // Height (without status and toolbar)
              
                  return Scaffold(
                    appBar: AppBar(),
                    body: RefreshIndicator(
                      onRefresh: () {
                        return Future.delayed(
                          Duration(seconds: 1),
                              () {
                          },
                        );
                      }, child: SingleChildScrollView(
                          physics: AlwaysScrollableScrollPhysics(),
                          child: Container(
                            color: Colors.red,
                            height: netHeight,
                          )
                    ),
                    ),
                  );
                }
              }
              

              结果如下:

              【讨论】:

                【解决方案11】:

                您可以使用CustomScrollView 和只有一个孩子SliverFillRemaining 作为我不显示数据小部件的情况:

                CustomScrollView(
                    slivers: [
                    SliverFillRemaining(
                        child: Center(
                        child: Text(
                            AppLocalizations.of(context).noData,
                        ),
                        ),
                    )
                    ],
                )
                

                【讨论】:

                  猜你喜欢
                  • 2019-11-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-04-05
                  • 1970-01-01
                  • 2021-12-25
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多