Flutter:如何制作比一个屏幕长的表单
Flutter: How to make a Form that is longer than one screen
我想制作一个非常基本的 flutter form with validation. But, I will have more questions than will fit on one screen, so I put my form fields in a ListView,像这样:
class SurveyView extends StatefulWidget {
final Iterable<String> questions;
const SurveyView(this.questions, {Key? key}) : super(key: key);
@override
_SurveyViewState createState() => _SurveyViewState();
}
class _SurveyViewState extends State<SurveyView> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 10),
children: widget.questions
.map((q) => SurveyQuestionView(q))
.toList()
.cast<Widget>() +
[
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Ok!')));
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Some form fields missing')));
}
},
child: Text("Submit")),
],
),
),
),
],
);
}
}
class SurveyQuestionView extends StatelessWidget {
final String question;
const SurveyQuestionView(this.question, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
width: double.maxFinite,
child: Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(10),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(question),
TextFormField(
validator: (value) {
if (value == null value.isEmpty) {
return 'Please enter a value';
}
},
),
]),
),
),
);
}
}
这对一些字段非常有效,但是当列表太长时,离屏幕太远的值似乎会丢失。当我点击“提交”时,验证只会上升一点点超过当前屏幕的开始。我假设这是对长列表的优化,但我如何保存我的状态并使表单验证检查整个列表。我尝试将 SurveyQuestionView
转换为有状态并对文本字段使用 controllers,但这没有帮助。
我是否只需要手动完成所有表单验证?或者有什么方法可以让内置表单处理这个问题?
或者,列表永远不会那么长。是否可以关闭此优化或使用不同类型的滚动视图?
如果您将小部件放入列中,则应关闭优化。但是您不能直接滚动列。输入 SingleChildScrollView。这是一个小部件,可让您滚动将成为其子部件的单个小部件。
所以更改此代码:
Form(
key: _formKey,
child: ListView(
etc.
至
Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
etc.
我想制作一个非常基本的 flutter form with validation. But, I will have more questions than will fit on one screen, so I put my form fields in a ListView,像这样:
class SurveyView extends StatefulWidget {
final Iterable<String> questions;
const SurveyView(this.questions, {Key? key}) : super(key: key);
@override
_SurveyViewState createState() => _SurveyViewState();
}
class _SurveyViewState extends State<SurveyView> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 10),
children: widget.questions
.map((q) => SurveyQuestionView(q))
.toList()
.cast<Widget>() +
[
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Ok!')));
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Some form fields missing')));
}
},
child: Text("Submit")),
],
),
),
),
],
);
}
}
class SurveyQuestionView extends StatelessWidget {
final String question;
const SurveyQuestionView(this.question, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
width: double.maxFinite,
child: Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(10),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(question),
TextFormField(
validator: (value) {
if (value == null value.isEmpty) {
return 'Please enter a value';
}
},
),
]),
),
),
);
}
}
这对一些字段非常有效,但是当列表太长时,离屏幕太远的值似乎会丢失。当我点击“提交”时,验证只会上升一点点超过当前屏幕的开始。我假设这是对长列表的优化,但我如何保存我的状态并使表单验证检查整个列表。我尝试将 SurveyQuestionView
转换为有状态并对文本字段使用 controllers,但这没有帮助。
我是否只需要手动完成所有表单验证?或者有什么方法可以让内置表单处理这个问题?
或者,列表永远不会那么长。是否可以关闭此优化或使用不同类型的滚动视图?
如果您将小部件放入列中,则应关闭优化。但是您不能直接滚动列。输入 SingleChildScrollView。这是一个小部件,可让您滚动将成为其子部件的单个小部件。
所以更改此代码:
Form(
key: _formKey,
child: ListView(
etc.
至
Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
etc.