如何使用 Flutter 创建带有固定页脚的滚动视图?

Mig*_*ivo 12 layout dart flutter

我想创建一个视图,无论屏幕大小如何,它都必须具有Column滚动视图(例如类似的东西SingleChildScrollView)和页脚。如果屏幕足够大,它将使用滚动和页脚之间的空白空间,如果不是,它将扩展并且只使页脚上方的小部件可滚动。

它或多或少类似于底部带有滚动页脚的 Listview,但不同之处在于我希望键盘溢出页脚并且它也应该保持原位。

就像是

例子

return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          SingleChildScrollView(
            child: Padding(
              padding: const EdgeInsets.only(left: 30.0, right: 30.0, top: 80.0),
              child: Form(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  children: <Widget>[
                   // Multiple widgets and form fields
                  ],
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(top: 50.0),
            child: SafeArea(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  // Footer widgets
                ],
              ),
            ),
          )
        ],
      ),
    );
Run Code Online (Sandbox Code Playgroud)

Mig*_*ivo 14

即使雷米的答案是正确的,我居然发现一个简单的方法来实现我是通过刚好结合寻找LayoutBuilderIntrinsicHeight

class ScrollableFooter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
      return SingleChildScrollView(
        child: ConstrainedBox(
          constraints: constraints.copyWith(
            minHeight: constraints.maxHeight,
            maxHeight: double.infinity,
          ),
          child: IntrinsicHeight(
            child: Column(
              children: <Widget>[
               // Your body widgets here
                Expanded(
                  child: Align(
                    alignment: Alignment.bottomCenter,
                    child: // Your footer widget
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 太棒了,在我看来比响应 MediaQuery 干净得多。 (4认同)

Fer*_*sta 10

公认的解决方案在许多情况下都有效,但当您想使用 ListView 之类的东西时,它会变得很棘手,因为它无法提供内在高度。我试图找到一些不同的解决方案,结果证明我可以,而且看起来更灵活。我设法使用条子解决了这种情况。内容位于条子内,页脚也位于条子内。

提示:观看“The Boring Flutter Development Show,Ep. 12”,其中全部都是关于 slivers 的。

return Scaffold(
  body: CustomScrollView(
    shrinkWrap: true,
    slivers: [
      SliverToBoxAdapter(
        child: Column(
          children: [
            //content widgets
          ],
        ),
      ),
      SliverFillRemaining(
        hasScrollBody: false,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            //footer widgets,
          ],
        ),
      ),
    ],
  ),
);
Run Code Online (Sandbox Code Playgroud)


Rém*_*let 7

困难在于Column,我们SingleChildScrollView很难一起工作,因为一个需要约束,而另一个则消除约束。

诀窍是使用 aCustomMultiChildLayout并自己进行计算。帮助MediaQuery获取键盘的大小,以便页脚可以消失,为内容留出更多空间。

这是一个可重复使用的小部件,可以为您完成此操作:

class FooterLayout extends StatelessWidget {
  const FooterLayout({
    Key key,
    @required this.body,
    @required this.footer,
  }) : super(key: key);

  final Container body;
  final Container footer;

  @override
  Widget build(BuildContext context) {
    return CustomMultiChildLayout(
      delegate: _FooterLayoutDelegate(MediaQuery.of(context).viewInsets),
      children: <Widget>[
        LayoutId(
          id: _FooterLayout.body,
          child: body,
        ),
        LayoutId(
          id: _FooterLayout.footer,
          child: footer,
        ),
      ],
    );
  }
}

enum _FooterLayout {
  footer,
  body,
}

class _FooterLayoutDelegate extends MultiChildLayoutDelegate {
  final EdgeInsets viewInsets;

  _FooterLayoutDelegate(this.viewInsets);

  @override
  void performLayout(Size size) {
    size = Size(size.width, size.height + viewInsets.bottom);
    final footer =
        layoutChild(_FooterLayout.footer, BoxConstraints.loose(size));

    final bodyConstraints = BoxConstraints.tightFor(
      height: size.height - max(footer.height, viewInsets.bottom),
      width: size.width,
    );

    final body = layoutChild(_FooterLayout.body, bodyConstraints);

    positionChild(_FooterLayout.body, Offset.zero);
    positionChild(_FooterLayout.footer, Offset(0, body.height));
  }

  @override
  bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
    return true;
  }
}
Run Code Online (Sandbox Code Playgroud)

如此使用:

FooterLayout(
  body: body,
  footer: footer,
),
Run Code Online (Sandbox Code Playgroud)


小智 6

我解决这个问题的方法是将固定的Footer和 The包装SingleChildScrollView在一个Stack小部件中,然后相应地对齐Footer


class ScrollableFooter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        SingleChildScrollView(
          child: Container(
            padding: EdgeInsets.all(5),
            child: Column(
              children: <Widget>[
                // Your body widgets here
              ],
            ),
          ),
        ),
        Align(
          alignment: Alignment.bottomCenter,
          child: // Your fixed Footer here,
        ),
      ],
    );
  }
}

Run Code Online (Sandbox Code Playgroud)


abh*_*thi 5

对于那些希望以简单的方式使用滚动视图实现页脚的人,下面的代码可能会有所帮助:

Scaffold(
      appBar: buildAppBar('Some cool appbar'),
      body: Column(
        children: [
          Expanded(
            child: SingleChildScrollView(
              child: Column(
                children: [
                  PackageCard(),
                  PackageCard(),
                  PackageCard(),
                ],
              ),
            ),
          ),
          Container(
            child: Text('Your super cool Footer'),
            color: Colors.amber,
          )
        ],
      ),
    );
Run Code Online (Sandbox Code Playgroud)

视觉表现:-

---Column
    |
    |---Expanded--
                 |-SingleChildScrollView (column /YOUR SCROLLABLE VIEW)
    |
    |-Container(YOUR FOOTER)
Run Code Online (Sandbox Code Playgroud)

我曾经expandedSinglechildScrollView过这里

  • 谢谢。它也适用于固定标题内容。只需将“YOUR FOOTER”代码片段交换到顶部内容之前。 (2认同)
  • 简单而优雅的解决方案...不知道为什么它不被接受为答案 (2认同)