如何用Flutter创建一个固定页脚的滚动视图?

wvyml7n5  于 2023-04-22  发布在  Flutter
关注(0)|答案(7)|浏览(116)

我想创建一个视图,它必须有一个带有滚动视图的Column(例如,类似SingleChildScrollView的东西)和一个页脚,而不管屏幕大小。如果屏幕足够大,它将使用滚动和页脚之间的空白空间,如果不是,它将扩展并仅使页脚上方的小部件可滚动。
它或多或少像Listview with scrolling Footer at the bottom,但有一个区别,我希望键盘溢出页脚,它也应该留在原地。
就像

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

5w9g7ksd1#

对于那些希望以简单的方式实现just footer with scrollview的人,下面的代码可能会有所帮助:

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

ruarlubt

ruarlubt2#

尽管Rémi的答案是正确的,但我实际上找到了一种更简单的方法来实现我所寻找的东西,只需将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
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    });
  }
}
ztigrdn8

ztigrdn83#

在许多情况下,公认的解决方案都是有效的,但是当你想使用ListView之类的东西时,它就变得很棘手了,因为它不能提供固有的高度。我试图找到一些不同的解决方案,结果证明我可以,而且它似乎更灵活。我设法使用slivers解决了这种情况。其中内容在一个sliver中,页脚也在一个sliver中。
提示:观看“无聊的Flutter发展显示,第12集”,这是所有关于条子。

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

igsr9ssn4#

我解决这个问题的方法是将固定的Footer和The SingleChildScrollView Package 在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,
        ),
      ],
    );
  }
}
vnjpjtjt

vnjpjtjt5#

困难在于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,
),
carvr3hs

carvr3hs6#

虽然公认的答案似乎适用于移动的设备,但当宽度(远)大于高度时就会出现问题。当这种情况发生时,IntrinsicHeight就像AspectRatio一样,高度增加,所以页脚被推离屏幕。
我认为问题在于IntrinsicHeight对其内部工作的定义:
......而是将自身调整到更合理的高度。
我可以确认@Rémi的解决方案在这些情况下也有效。
它应该成为Flutter框架提供的标准小部件。

58wvjzkj

58wvjzkj7#

要创建一个具有可滚动屏幕的页脚,我们可以使用ListView.builder和SingleChildScrollview的堆栈小部件:

Scaffold(
      body:Stack(
        alignment: Alignment.bottomCenter, 
        children: [
          ListView.builder(
            itemCount: 1,
            itemBuilder: (context, index) => SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Container( // Scrollable contents here
                color: Colors.red,
                height: 3000,
                width: 1000,
              ),
            ),
          ),
          Container( // Footer
            height:50,
            color:Colors.blue[900],
            width:MediaQuery.of(context).size.width,
            child:Center(child:Text("Footer")),
          ),
        ],
      ),
    );

相关问题