Flutter:如何制作超过一屏的Form

Posted

技术标签:

【中文标题】Flutter:如何制作超过一屏的Form【英文标题】:Flutter: How to make a Form that is longer than one screen 【发布时间】:2021-06-02 18:47:51 【问题描述】:

我想通过验证制作一个非常基本的颤振form。但是,我的问题会比一个屏幕上显示的要多,所以我将表单字段放在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,但这没有帮助。

我是否只需要手动完成所有表单验证?或者有什么方法可以让内置的表单来处理这个问题?

或者,列表永远不会那么长。是否可以关闭此优化或使用其他类型的滚动视图?

【问题讨论】:

将表单字段放在单个滚动视图内的列中 【参考方案1】:

如果您将小部件放入列中,则应关闭优化。但是你不能直接滚动一列。输入 SingleChildScrollView。它是一个小部件,可让您滚动将成为其子级的单个小部件。

所以更改此代码:

Form(
    key: _formKey,
    child: ListView(
        etc.

Form(
    key: _formKey,
    child: SingleChildScrollView(
        child: Column(
              etc.

【讨论】:

这确实有效,尽管它仍然不会自动滚动到第一个错误。在使用 Form 时能够保持实际 ListView 的性能优势会很好,但我想这是不可能的 我明白了。我相信我误解了你的问题。当您说“验证只增加一点”时,我假设您的意思是屏幕外项目的实际验证功能不起作用。但是,如果我理解正确,验证是有效的,但是如果屏幕外的某些内容在验证期间出现错误,它不会自动滚动到视图中,对吗?我看看能不能找到解决办法。 不,你是对的。以前,验证对屏幕外的项目根本不起作用,但它会自动滚动到它验证的第一个项目。使用此解决方案,实际验证工作正常,但似乎根本不会自动滚动,这是可以容忍的。

以上是关于Flutter:如何制作超过一屏的Form的主要内容,如果未能解决你的问题,请参考以下文章

storyboard怎么把舞台视图单独

XCUI 测试:app.debugDescription 显示最后一屏的信息

如何设置jquery fullpage每一屏的大小

swiper在vue中使用,纵向滚动翻页,超出一屏的解决方案

在用swiper框架的时候,怎样在第一屏的时候,阻止滑动事件

html中想让一部分内容一直显示在页面的最下方,页面内容不足一屏时显示在这一屏的最下方