刷新指示器没有滚动视图

Tre*_*rcy 14 flutter

我知道一个ListViewSingleChildScrollView RefreshIndicator只是本地工作,但我想RefreshIndicator在一个不滚动的页面上使用.这是否可能,如果是这样,怎么样?

Roh*_*eja 33

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

我有一个用例*,它不起作用,因为里面的内容想要SingleChildScrollView扩展以填充剩余的高度。所以 theSingleChildScrollViewExpandedwidgets 是相互矛盾的。

最终,使用CustomScrollView带有SliverFillRemaining小部件的方法挽救了局面。

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

使用自定义滚动视图拉动刷新

代码:

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."),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

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

*我的用例:

拉动刷新复杂案例


小智 29

您必须执行以下操作:

  • 使用SingleChildScrollView属性physics设置为a 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,
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 15

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

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

  • 这也是我用的。但对于列表视图上方需要用户点击按钮的小部件,它不起作用。 (2认同)

mak*_*mba 10

我同意其他人关于SingleChildScrollView解决方案的观点。不过,它在 Android 和 ios 上的工作方式有所不同。

在 Android 上一切都很好,但在 ios 上你会得到一个非常丑陋的过度滚动行为。

在此输入图像描述

您将无法通过使用ClampingScrollPhysics而不是修复此行为AlwaysScrollableScrollPhysics,因为它会破坏RefreshIndicator

一个非常好的选择是覆盖默认值,ScrollConfiguration这样它在两个平台上看起来都是一样的

这是自定义小部件的完整代码:

import 'package:flutter/material.dart';

// NOTE: this is really important, it will make overscroll look the same on both platforms
class _ClampingScrollBehavior extends ScrollBehavior {
  @override
  ScrollPhysics getScrollPhysics(BuildContext context) => ClampingScrollPhysics();
}

class NonScrollableRefreshIndicator extends StatelessWidget {
  final Widget child;
  final Future<void> Function() onRefresh;

  const NonScrollableRefreshIndicator({
    required this.child,
    required this.onRefresh,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: ((_, constraints) {
        return RefreshIndicator(
          onRefresh: onRefresh,
          child: ScrollConfiguration(
            // Customize scroll behavior for both platforms
            behavior: _ClampingScrollBehavior(),
            child: SingleChildScrollView(
              physics: AlwaysScrollableScrollPhysics(),
              child: ConstrainedBox(
                constraints: BoxConstraints(
                  minHeight: constraints.maxHeight,
                  maxHeight: constraints.maxHeight
                ),
                child: child,
              ),
            ),
          ),
        );
      }),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

它在两个平台上的行为都是这样的: 在此输入图像描述


小智 7

大多数其他答案都有效,但它们都有一些缺点。使用aSingleChildScrollView而不调整高度会导致“滚动发光效果”不在页面底部。将高度设置为当前视图的最大高度(通过使用MediaQuery或 a LayoutBuilder)将解决此问题,但是当您的内容高度大于可用空间的高度时,将会出现渲染溢出。

最后,以下解决方案对我来说完美无缺,没有任何问题:

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


Nic*_*nko 6

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

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


Par*_*iya 6

推荐使用AlwaysScrollableScrollPhysics()withRefreshIndicator因为如果Scrollable可能没有足够的内容来过度滚动,请考虑将其physics属性设置为AlwaysScrollableScrollPhysics

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

ListView(
  physics: const AlwaysScrollableScrollPhysics(),
  children: ...
)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

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


Arn*_*rge 3

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

-不。


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

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

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

通常是 [ListView] 或 [CustomScrollView]。


有解决方法吗?

-是的

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

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