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.