Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Layout 如何创建带有固定页脚和颤振的滚动视图?_Layout_Dart_Flutter - Fatal编程技术网

Layout 如何创建带有固定页脚和颤振的滚动视图?

Layout 如何创建带有固定页脚和颤振的滚动视图?,layout,dart,flutter,Layout,Dart,Flutter,我想创建一个视图,该视图必须有一个带有滚动视图的列(例如类似SingleChildScrollView)和一个页脚,而不管屏幕大小如何。如果屏幕足够大,它将使用滚动条和页脚之间的空白,如果没有,它将展开并只使页脚上方的小部件可滚动 这或多或少有点像,但有一点不同,我希望键盘溢出页脚,它也应该留在原地 差不多 返回脚手架( 正文:专栏( mainAxisAlignment:mainAxisAlignment.spaceBetween, 儿童:[ SingleChildScrollView( 孩子

我想创建一个视图,该视图必须有一个带有滚动视图的
(例如类似
SingleChildScrollView
)和一个页脚,而不管屏幕大小如何。如果屏幕足够大,它将使用滚动条和页脚之间的空白,如果没有,它将展开并只使页脚上方的小部件可滚动

这或多或少有点像,但有一点不同,我希望键盘溢出页脚,它也应该留在原地

差不多

返回脚手架(
正文:专栏(
mainAxisAlignment:mainAxisAlignment.spaceBetween,
儿童:[
SingleChildScrollView(
孩子:填充(
填充:仅限常量边集(左:30.0,右:30.0,顶部:80.0),
孩子:表格(
子:列(
crossAxisAlignment:crossAxisAlignment.stretch,
儿童:[
//多个窗口小部件和表单字段
],
),
),
),
),
填充物(
填充:仅限常量边集(顶部:50.0),
儿童:安全区(
孩子:排(
mainAxisAlignment:mainAxisAlignment.spaceBetween,
儿童:[
//页脚小部件
],
),
),
)
],
),
);

困难在于
SingleChildScrollView
很难一起工作,因为一个需要约束,另一个需要删除约束

诀窍是使用
自定义多子女布局
,然后自己进行计算。借助
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;
  }
}

尽管Rémi的答案是正确的,但实际上我已经找到了一种更简单的方法,通过将
LayoutBuilder
IntrinsicHeight
相结合来实现我想要的目标

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
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    });
  }
}
类ScrollableFooter扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回布局生成器(
生成器:(BuildContext上下文,BoxConstraints){
返回SingleChildScrollView(
子:约束框(
约束:constraints.copyWith(
最小高度:constraints.maxHeight,
maxHeight:double.infinity,
),
孩子:内在的(
子:列(
儿童:[
//你的身体部件在这里
扩大(
子对象:对齐(
对齐:对齐.bottomCenter,
child://您的页脚小部件
),
),
],
),
),
),
);
});
}
}

我解决这个问题的方法是将固定的
页脚
SingleChildScrollView
包装在
堆栈
小部件中,然后相应地对齐
页脚


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


类ScrollableFooter扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回堆栈(
儿童:[
SingleChildScrollView(
子:容器(
填充:边缘设置。全部(5),
子:列(
儿童:[
//你的身体部件在这里
],
),
),
),
对齐(
对齐:对齐.bottomCenter,
child://此处是您的固定页脚,
),
],
);
}
}

虽然公认的答案似乎适用于移动设备,但当宽度(远)大于高度时,就会出现问题。当这种情况发生时,
IntrinsicHeight
就像一个
AspectRatio
,高度增加,因此页脚被推出屏幕

我认为问题在于其内部工作的定义:

。。。取而代之的是把自己的尺寸调整到一个更合理的高度

我可以证实@Rémi的解决方案在这些情况下也有效


它应该是颤振框架提供的一个标准小部件。

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

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)

我在这里使用了
expanded
SinglechildScrollView

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

小贴士:看“无聊的颤振发展秀,第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,
          ],
        ),
      ),
    ],
  ),
);

你能提供一份所需布局的小草稿吗?@RémiRousselet完成了。我更想的是一张截图/图纸。某物visual@RémiRousselet补充道:
footer:footer
有一个问题,我加入了
footer:TextField(…)
,当点击输入时,我的键盘会在页脚区域弹出并隐藏TextField区域,我认为这比响应MediaQuerys要干净得多。你也可以使用
Spacer()
而不是Expanded@RomanPanaget在某些情况下,将无法正常工作,因为您希望将可用空间分配给页脚小部件,并将其与底部的空间对齐。使用
Spacer()
您将有另一个“空”小部件使用中间的空格,并且页脚实际上将缩小到最大尺寸。检查它,结果是sameThanks。它也适用于固定标题内容。只需要将“YOUR FOOTER”代码片段交换到t
---Column
    |
    |---Expanded--
                 |-SingleChildScrollView (column /YOUR SCROLLABLE VIEW)
    |
    |-Container(YOUR FOOTER)
return Scaffold(
  body: CustomScrollView(
    shrinkWrap: true,
    slivers: [
      SliverToBoxAdapter(
        child: Column(
          children: [
            //content widgets
          ],
        ),
      ),
      SliverFillRemaining(
        hasScrollBody: false,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            //footer widgets,
          ],
        ),
      ),
    ],
  ),
);