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