如何在Flutter中滚动页面

111

我的页面代码是这样的。我需要滚动AppBar下面的部分。

@override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(... ),
      body: new Stack(
        children: <Widget>[
          new Container(
            decoration: BoxDecoration(
                image: DecorationImage(...),
          new Column(children: [
            new Container(...),
            new Container(...... ),
            new Padding(
              child: SizedBox(
                child: RaisedButton(..),
            ),
            new Divider(),
            new Column(
              children: <Widget>[
                new Container(
                  child: new Row(
                    children: <Widget>[
                      new Expanded(
                        child: new Text(  ),
                      ),
                      new IconButton(
                        icon: IconButton(..),
                        onPressed: () {
                          _changed(true, "type");
                        },
                      ),
                    ],
                  ),
                ),
                visibilityPropertyType
                    ? new Container(
                        margin: EdgeInsets.all(24.0),
                        child: new Column(
                          children: <Widget>[
                            new Row(
                              children: <Widget>[
                                new Expanded(... ),
                                new RaisedButton(..)
                              ],
                            ),
                            new Padding(
                              padding: const EdgeInsets.only(top: 10.0),
                              child: new Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceEvenly,
                                children: <Widget>[
                                  new Column(
                                    children: <Widget>[
                                      new Row(  
                                        children: <Widget>[.. ]),
                                      new Row(
                                        children: <Widget>[]),
                                      new Row(
                                        children: <Widget>[]),
                                      new Row(
                                        children: <Widget>[],
                                  ),
                                  new Column(
                                    children: <Widget>[
                                      new Row(
                                        children: <Widget>[],
                                      ),
                                    ],
                                  ),
                                ],
                              ),
                            ),
                          ],
                        ))
                    : new Container(),
              ],
            ),
            new Divider(
              color: Colors.white,
            )
          ])
        ],
      ),
    );
  }

我需要让页面的部分内容可以滚动,你能帮我实现这个功能吗?如果有现成的自定义滚动方法,麻烦告诉我一下。我已经尝试了 Scrollable 和 SingleChildScrollView,但都不能满足我的需求。当我使用 SinglechildScrollView 时,会出现 BoxConstraints 强制无限高度的错误。如果我移除 LayoutBuilder,就会出现 RenderFlex 在底部溢出 22 个像素的错误。
9个回答

225

将您的小部件树包装在 SingleChildScrollView 中:

 body: SingleChildScrollView(
child: Stack(
    children: <Widget>[
      new Container(
        decoration: BoxDecoration(
            image: DecorationImage(...),
      new Column(children: [
        new Container(...),
        new Container(...... ),
        new Padding(
          child: SizedBox(
            child: RaisedButton(..),
        ),
....
...
 ); // Single child scroll view

请记住,SingleChildScrollView只能有一个直接的小部件(就像Android中的ScrollView一样)。


36
我遇到了一个错误:RenderFlex children have non-zero flex but incoming height constraints are unbounded.,意思是我的代码出现了问题,可能是因为我使用了具有非零flex属性的组件,但是没有给它们设置高度限制。 - Twometer
2
你在SingleChildScrollView中使用了ListView或其他可滚动的控件吗?如果是,将该控件的shringWrap属性设置为true可能会解决问题。 - Jaswant Singh
7
如果您有扩展组件,请尝试将其删除。 - Rony Tesler
很高兴我选择了Stack Overflow。谷歌建议使用DraggableScrollableSheet,但那看起来需要更多的工作,而且并不完全符合需求。为Stack Overflow点赞。 - Nick N
Spacer() 也会导致 RenderFlex children have non-zero flex but incoming height constraints are unbounded. 问题。 - kris

39

有了您的建议,我得出了这样的解决方案:

new LayoutBuilder(
        builder:
            (BuildContext context, BoxConstraints viewportConstraints) {
          return SingleChildScrollView(
            child: ConstrainedBox(
              constraints:
                  BoxConstraints(minHeight: viewportConstraints.maxHeight),
              child: Column(children: [
             // remaining stuffs
              ]),
            ),
          );
        },
      )

6
使用 LayoutBuilder + BoxConstraints + ConstrainedBox 可以创造奇迹!例如,在我的情况下,我想要在列中嵌套一个水平滚动。问题是,默认情况下,水平滚动不管怎样都会将其内容居中显示。因此,我必须将 SingleChildScrollView 放在带有 maxWidth: viewportConstraints.maxWidth, minWidth: viewportConstraints.maxWidth 的 ConstrainedBox 中。这样,如果内容很少,它就会靠左对齐,如果内容很多(超过屏幕宽度),则开始滚动。 - Kirill Karmazin
这个解决方案是可行的,但布局构建器在页面发生任何交互时都会构建所有小部件,例如滚动列表、点击按钮。这样好吗?如果您想检查它是否重建,则可以从pub加载randomColor库并将其分配给页面中的任何小部件。您尝试与布局构建器下的任何小部件进行交互。您可以看到每次分配了randomColor的小部件都会改变颜色。这样好吗?需要专家建议。 - Thiyraash David
布局构建器在任何子小部件交互时都会重新渲染子小部件。 - Jaswant Singh
这个答案对我来说是一个小奇迹。我一直在努力让可滚动列表的高度与堆栈中最大子元素的高度相匹配。你的代码示例对我非常有帮助。谢谢! - Adrian Moisa

34

页面添加滚动条的两种方法

1. 使用SingleChildScrollView:

     SingleChildScrollView(
          child: Column(
            children: [
              Container(....),
              SizedBox(...),
              Container(...),
              Text(....)
            ],
          ),
      ),
      

2. 使用ListView: ListView是默认提供的滚动控件,无需添加额外的控件来实现滚动。

     ListView(
          children: [
            Container(..),
            SizedBox(..),
            Container(...),
            Text(..)
          ],
      ),
      

8
您可以尝试使用CustomScrollView,将其放置在Column Widget中。

以示例为例 -

class App extends StatelessWidget {

 App({Key key}): super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(
          title: const Text('AppBar'),
      ),
      body: new Container(
          constraints: BoxConstraints.expand(),
          decoration: new BoxDecoration(
            image: new DecorationImage(
              alignment: Alignment.topLeft,
              image: new AssetImage('images/main-bg.png'),
              fit: BoxFit.cover,
            )
          ),
          child: new Column(
            children: <Widget>[               
              Expanded(
                child: new CustomScrollView(
                  scrollDirection: Axis.vertical,
                  shrinkWrap: false,
                  slivers: <Widget>[
                    new SliverPadding(
                      padding: const EdgeInsets.symmetric(vertical: 0.0),
                      sliver: new SliverList(
                        delegate: new SliverChildBuilderDelegate(
                          (context, index) => new YourRowWidget(),
                          childCount: 5,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          )),
    );
  }
}

在上面的代码中,我展示了一个包含5个项目的列表,使用了CustomScrollView控件。 YourRowWidget小部件作为列表项被渲染了5次。通常情况下,您应该根据一些数据来呈现每一行。
您可以移除Container小部件的decoration属性,它仅用于提供背景图片。

6

You can use this one and it's best practice.

SingleChildScrollView(
  child: Column(
    children: <Widget>[
      //Your Widgets
      //Your Widgets,
      //Your Widgets
    ],
  ),
);

5

如果您已经在使用statelessWidget,那么这将非常容易。请查看我的代码。

class _MyThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Understanding Material-Cards'),
      ),
      body: SingleChildScrollView(
          child: Column(
        children: <Widget>[
          _buildStack(),
          _buildCard(),
          SingleCard(),
          _inkwellCard()
        ],
      )),
    );
  }
}

1

看这个,可能会帮到你。

class ScrollView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new LayoutBuilder(
      builder:
          (BuildContext context, BoxConstraints viewportConstraints) {
        return SingleChildScrollView(
          scrollDirection: Axis.vertical,
          child: ConstrainedBox(
            constraints: BoxConstraints(minHeight: viewportConstraints.maxHeight),
            child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text("Hello world!!"),
                  //You can add another children
            ]),
          ),
        );
      },
    );
  }
}

0

添加这个可能会解决你的问题,将高度设置为max(screenSize.height, 1024)


0

您可以以两种方式滚动内容的任何部分...

  1. 您可以直接使用列表视图
  2. 或SingleChildScrollView

大多数情况下,当特定屏幕中有键盘交互时,我直接使用列表视图,以便内容不会被键盘覆盖,并且可以向上滚动到顶部....

这个技巧在很多时候都会很有帮助....


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接