我目前正在为类似信息亭的设备编写Flutter应用。该设备将以横向模式安装,底部具有集成的条形码扫描仪。
设备将几乎所有时间都花在单个布局上:
当前,整个主体位于SingleChildScrollView中。当用户在文本输入框中点按时,这可使视图“向上滑动”。然后,当键盘关闭时,视图会向后“滑动”。
我想做的是至少在可见时(当键盘不覆盖它时)将底部的“ Scan Ticket Under”行固定在视图的底部。截至目前,它是一种弹性布局,还没有完全触底。
使用调试画图查看图像:粉红色的框应位于底部,上方的所有内容均应处于可滚动视图中。
我开始搞各种各样的选择。我不需要固定位置,因为我们最终还将使解决方案在具有各种屏幕尺寸的iDevice上可用。
这是我目前的脚手架:
Container(
constraints: BoxConstraints.expand(),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.only(top: 50.0, bottom: 20.0),
child: Text(_message ?? "Welcome!",
textAlign: TextAlign.center,
style:
TextStyle(fontSize: 45.0, color: Colors.black)),
),
Padding(
padding: EdgeInsets.all(20.0),
child: Text("Scan ticket below or Search for your Transaction",
style:
TextStyle(fontSize: 25.0, color: Colors.black)),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
flex: 4,
child: Container(
margin: EdgeInsets.symmetric(
horizontal: 50.0, vertical: 25.0),
color: skidataThemeData.primaryColor,
padding: const EdgeInsets.symmetric(
horizontal: 25.0, vertical: 25.0),
child: Center(
child: new TextFormField(
//This autofocus works, but during transition from successful plate val to
//this page, the keyoard is activated during transition causing an overflow on the
//applyValidationScreen.
//autofocus: true,
style: new TextStyle(
decorationColor:
skidataThemeData.accentColor,
fontSize: 90.0,
color: skidataThemeData.accentColor),
textAlign: TextAlign.center,
onSaved: (String value) {
this._data.plateNumber = value;
},
decoration: new InputDecoration(
hintText: "Enter Data",
hintStyle: new TextStyle(
color: Colors.white),
fillColor:
skidataThemeData.accentColor,
contentPadding: EdgeInsets.all(1.0),
border: InputBorder.none),
validator: (value) {
if (value.isEmpty) {
return 'Field cannot be blank.';
}
},
autocorrect: false,
),
))),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.all(25.0),
child: RaisedButton(
padding: EdgeInsets.all(15.0),
color: skidataThemeData.accentColor,
onPressed: () async {
FocusScope.of(context)
.requestFocus(new FocusNode());
setState(() {
_message = '';
});
if (_formKey.currentState.validate()) {
// If the form is valid, we want to show a Snackbar
Scaffold.of(context).showSnackBar(
new SnackBar(
content: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
new CircularProgressIndicator(
valueColor:
new AlwaysStoppedAnimation<
Color>(
skidataThemeData
.primaryColor),
),
Text(
'Search for matching record..',
style: new TextStyle(
color: skidataThemeData
.primaryColor))
],
),
backgroundColor:
skidataThemeData.accentColor,
duration: Duration(seconds: 10)),
);
await new Future.delayed(
const Duration(milliseconds: 1000));
Scaffold.of(context)
.hideCurrentSnackBar();
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
new SvalKioskApp()),
);
} else {
setState(() {
_message = "";
});
}
},
child: new Text('Search for Record',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25.0, color: Colors.black)),
),
))
]),
Container(
color: Colors.pink,
child: Padding(
padding: const EdgeInsets.only(top:40.0),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.symmetric(
horizontal: 10.0, vertical: 5.0),
child: Image.asset(
'images/downarrow.png',
fit: BoxFit.contain,
),
)),
Expanded(
flex: 5,
child: Center(
child: Text("Scan Physical Ticket Below!",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 45.0)))),
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.symmetric(
horizontal: 10.0, vertical: 5.0),
child: Image.asset(
'images/downarrow.png',
fit: BoxFit.contain,
),
)),
]),
),
)
]),
),
)
答案 0 :(得分:1)
今天早上我在洗澡时,解决方案使我震惊:
从一列开始,您将其分为两个扩展小部件以获取所需的顶部/底部部分配比。
然后在每个Expanded中,将一个子容器扩展为填充空间。在顶部容器中,将对齐方式设置为topCenter,将底部容器中的对齐方式设置为bottomCenter
在顶部容器中,添加SingleChildScrollView子级。现在,上部是可滚动的,底部是固定的。
Widget getInputView() {
return Builder(
builder: (context) => Container(
constraints: BoxConstraints.expand(),
child: Column(
children: <Widget>[
Expanded(
flex: 4,
child: Container(
alignment: Alignment.topCenter,
constraints: BoxConstraints.expand(),
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: [
Text("${_kiosk.kioskName}",
textAlign: TextAlign.end)
]),
),
Padding(
padding: EdgeInsets.symmetric(vertical:30.0),
child: Text(
_kiosk.displayMessage ?? "Welcome!",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 45.0,
color: Colors.black)),
),
Padding(
padding: EdgeInsets.all(20.0),
child: Text(
"Scan barcode below or enter search data in box.",
style: TextStyle(
fontSize: 25.0,
color: Colors.black)),
),
Row(
mainAxisAlignment:
MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
flex: 4,
child: Container(
margin: EdgeInsets.symmetric(
horizontal: 50.0,
vertical: 25.0),
color: themeData
.primaryColor,
padding: const EdgeInsets
.symmetric(
horizontal: 25.0,
vertical: 25.0),
child: Center(
child: new TextFormField(
//This autofocus works, but during transition from successful plate val to
//this page, the keyoard is activated during transition causing an overflow on the
//applyValidationScreen.
//autofocus: true,
style: new TextStyle(
decorationColor:
themeData
.accentColor,
fontSize: 90.0,
color:
themeData
.accentColor),
textAlign:
TextAlign.center,
onSaved: (String value) {
this._data.plateNumber =
value;
},
decoration: new InputDecoration(
hintText:
"Enter Data",
hintStyle:
new TextStyle(
color: Colors
.white),
fillColor:
themeData
.accentColor,
contentPadding:
EdgeInsets.all(
1.0),
border:
InputBorder.none),
validator: (value) {
if (value.isEmpty) {
return 'Field cannot be blank.';
}
},
autocorrect: false,
),
))),
Expanded(
flex: 1,
child: Padding(
padding:
const EdgeInsets.all(25.0),
child: RaisedButton(
padding: EdgeInsets.all(15.0),
color: themeData
.accentColor,
onPressed: () async {
FocusScope.of(context)
.requestFocus(
new FocusNode());
if (_formKey.currentState
.validate()) {
// If the form is valid, we want to show a Snackbar
Scaffold.of(context)
.showSnackBar(
new SnackBar(
content: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
new CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<
Color>(
themeData
.primaryColor),
),
Text(
'Search for matching ticket..',
style: new TextStyle(
color: themeData
.primaryColor))
],
),
backgroundColor:
themeData
.accentColor,
duration: Duration(
seconds: 10)),
);
await new Future.delayed(
const Duration(
milliseconds:
1000));
PlateMatchResponse resp =
await this.submit();
Scaffold.of(context)
.hideCurrentSnackBar();
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) =>
new SvalKioskApp()),
);
}
},
child: new Text(
'Search for Data Match',
textAlign:
TextAlign.center,
style: TextStyle(
fontSize: 25.0,
color: Colors.black)),
),
))
]),
]),
),
))),
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.all(25.0),
alignment: Alignment.bottomCenter,
constraints: BoxConstraints.expand(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.symmetric(
horizontal: 10.0, vertical: 5.0),
child: Image.asset(
'images/downarrow.png',
fit: BoxFit.contain,
),
)),
Expanded(
flex: 5,
child: Center(
child: Text(
"Scan Physical Ticket Below",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 45.0)))),
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.symmetric(
horizontal: 10.0, vertical: 5.0),
child: Image.asset(
'images/downarrow.png',
fit: BoxFit.contain,
),
)),
])))
],
),
));
答案 1 :(得分:0)
如何将SingleChildScrollView
替换为Column
,然后将resizeToAvoidBottomPadding
的{{1}}属性设置为false,这样就不需要滚动视图了,因为键盘不会强制调整布局大小。