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

时间:2019-01-03 17:45:42

标签: layout dart flutter

我想创建一个视图,该视图必须具有Column和滚动视图(例如SingleChildScrollView之类)和页脚,而与屏幕大小无关。如果屏幕足够大,它将使用滚动条和页脚之间的空白空间;如果不足够,它将展开并且仅使页脚上方的小部件可滚动。

它或多或少像Listview with scrolling Footer at the bottom,但有一个不同,我希望键盘溢出页脚,并且它也应该留在原处。

类似

example

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

6 个答案:

答案 0 :(得分:3)

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

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

视觉表现:-

---Column
    |
    |---Expanded--
                 |-SingleChildScrollView (column /YOUR SCROLLABLE VIEW)
    |
    |-Container(YOUR FOOTER)

我在这里使用了 expandedSinglechildScrollView

答案 1 :(得分:2)

困难在于ColumnSingleChildScrollView很难一起工作,因为其中一个需要约束,而另一个需要约束。

诀窍是使用CustomMultiChildLayout自己进行计算。 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;
  }
}

照这样使用:

FooterLayout(
  body: body,
  footer: footer,
),

答案 2 :(得分:1)

我解决的方法是将固定的FooterSingleChildScrollView包装在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,
        ),
      ],
    );
  }
}

答案 3 :(得分:1)

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

提示:观看“The Boring Flutter Development Show, Ep. 12”,这都是关于条子的。

1

答案 4 :(得分:0)

尽管Rémi的答案是正确的,但实际上我已经找到了一种简单的方法,只需将LayoutBuilderIntrinsic Height结合起来即可实现自己的目标。

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
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    });
  }
}

答案 5 :(得分:0)

尽管公认的答案似乎在移动设备上有效,但是当宽度大于高度时会出现问题。发生这种情况时,IntrinsicHeight就像AspectRatio一样,并且高度增加,因此页脚被推离屏幕。

我认为问题在于IntrinsicHeight内部工作方式所使用的定义:

...而是将其自身调整为更合理的高度。

我可以确认@Rémi的解决方案在这种情况下也适用。

它应该是Flutter框架提供的标准小部件。