首页 > 解决方案 > 为什么 Form 中的 validate() 会跳过一些验证器(Flutter)?

问题描述

我的validate()功能有问题。我不明白为什么它会跳过一些validator:(){}。这是我的代码:

import 'package:flutter/material.dart';

class TestScreen extends StatefulWidget {
  static const routeName = '/test-screen';

  @override
  _TestScreenState createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  final _form = GlobalKey<FormState>();

  Future<void> _saveForm() async {
    final isValid = _form.currentState.validate();
    if (!isValid) {
      return;
    }
  }

  Widget _buildContainer(Widget child) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border.all(color: Colors.grey),
        borderRadius: BorderRadius.circular(10),
      ),
      margin: EdgeInsets.all(10),
      padding: EdgeInsets.all(10),
      height: 200,
      width: 300,
      child: child,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Test',
          style: Theme.of(context).textTheme.title,
        ),
        automaticallyImplyLeading: false,
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Form(
          key: _form,
          child: ListView(
            children: <Widget>[
              TextFormField(
                initialValue: '',
                decoration: InputDecoration(labelText: 'Name'),
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Insert something';
                  }
                  return null;
                },
              ),
              TextFormField(
                initialValue: '',
                decoration: InputDecoration(labelText: 'Number'),
                keyboardType: TextInputType.number,
                validator: (value) {
                  if (int.tryParse(value) == null) {
                    return 'Insert a number';
                  }
                  return null;
                },
              ),
              SizedBox(height: 20),
              _buildContainer(
                ListView(
                  children: <Widget>[],
                ),
              ),
              Text(
                'Text-Test1',
                textAlign: TextAlign.center,
              ),
              Slider(
                value: 1,
                divisions: 3,
                min: 0.0,
                max: 3.0,
                label: 'Test',
                onChanged: (newValue) {},
              ),
              SizedBox(
                height: 20,
              ),
              Text(
                'Text-Test2',
                textAlign: TextAlign.center,
              ),
              Slider(
                value: 3,
                divisions: 4,
                min: 0.0,
                max: 4.0,
                label: 'Nothing2',
                onChanged: (newValue) {},
              ),
              SizedBox(
                height: 20,
              ),
              Row(
                children: <Widget>[
                  Text('RandomLabel'),
                  Spacer(),
                  Container(
                    width: 100,
                    child: TextFormField(
                      initialValue: '',
                      keyboardType: TextInputType.number,
                      validator: (value) {
                        if (int.tryParse(value) == null) {
                          return 'Insert a number';
                        }
                        return null;
                      },
                    ),
                  ),
                ],
              ),
              SizedBox(
                height: 20,
              ),
              Text(
                'Test 2',
                textAlign: TextAlign.center,
              ),
              _buildContainer(
                ListView.builder(
                  itemCount: 0,
                  itemBuilder: (ctx, index) {
                    return ListTile(
                      title: Text('hello'),
                      subtitle: Text('world'),
                    );
                  },
                ),
              ),
              TextFormField(
                initialValue: '',
                minLines: 4,
                maxLines: 4,
                decoration: InputDecoration(labelText: 'Text'),
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Insert something';
                  }
                  return null;
                },
              ),
              FlatButton.icon(
                icon: Icon(Icons.check),
                label: Text('Done'),
                onPressed: () {
                  _saveForm();
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

如果我点击完成,它会跳过前两个TextFormField并去验证Row. 显然这不是我想要的。如何修复它并验证所有TextFormFields?

标签: formsflutter

解决方案


用包装表单字段ListView是一个坏主意:当用户滚动到submit按钮时,一些输入被释放,因为它们不在屏幕上。您必须ListViewColumn小部件替换并将所有表单包装在SingleChildScrollView

class TestScreen extends StatefulWidget {
  static const routeName = '/test-screen';

  @override
  _TestScreenState createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  final _form = GlobalKey<FormState>();

  Future<void> _saveForm() async {
    final isValid = _form.currentState.validate();
    if (!isValid) {
      return;
    }
  }

  Widget _buildContainer(Widget child) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border.all(color: Colors.grey),
        borderRadius: BorderRadius.circular(10),
      ),
      margin: EdgeInsets.all(10),
      padding: EdgeInsets.all(10),
      height: 200,
      width: 300,
      child: child,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Test',
          style: Theme.of(context).textTheme.title,
        ),
        automaticallyImplyLeading: false,
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Form(
            key: _form,
            child: Column(
              children: <Widget>[
                TextFormField(
                  initialValue: '',
                  decoration: InputDecoration(labelText: 'Name'),
                  validator: (value) {
                    if (value.isEmpty) {
                      return 'Insert something';
                    }
                    return null;
                  },
                ),
                TextFormField(
                  initialValue: '',
                  decoration: InputDecoration(labelText: 'Number'),
                  keyboardType: TextInputType.number,
                  validator: (value) {
                    if (int.tryParse(value) == null) {
                      return 'Insert a number';
                    }
                    return null;
                  },
                ),
                SizedBox(height: 20),
                _buildContainer(
                  ListView(
                    children: <Widget>[],
                  ),
                ),
                Text(
                  'Text-Test1',
                  textAlign: TextAlign.center,
                ),
                Slider(
                  value: 1,
                  divisions: 3,
                  min: 0.0,
                  max: 3.0,
                  label: 'Test',
                  onChanged: (newValue) {},
                ),
                SizedBox(
                  height: 20,
                ),
                Text(
                  'Text-Test2',
                  textAlign: TextAlign.center,
                ),
                Slider(
                  value: 3,
                  divisions: 4,
                  min: 0.0,
                  max: 4.0,
                  label: 'Nothing2',
                  onChanged: (newValue) {},
                ),
                SizedBox(
                  height: 20,
                ),
                Row(
                  children: <Widget>[
                    Text('RandomLabel'),
                    Spacer(),
                    Container(
                      width: 100,
                      child: TextFormField(
                        initialValue: '',
                        keyboardType: TextInputType.number,
                        validator: (value) {
                          if (int.tryParse(value) == null) {
                            return 'Insert a number';
                          }
                          return null;
                        },
                      ),
                    ),
                  ],
                ),
                SizedBox(
                  height: 20,
                ),
                Text(
                  'Test 2',
                  textAlign: TextAlign.center,
                ),
                _buildContainer(
                  ListView.builder(
                    itemCount: 0,
                    itemBuilder: (ctx, index) {
                      return ListTile(
                        title: Text('hello'),
                        subtitle: Text('world'),
                      );
                    },
                  ),
                ),
                TextFormField(
                  initialValue: '',
                  minLines: 4,
                  maxLines: 4,
                  decoration: InputDecoration(labelText: 'Text'),
                  validator: (value) {
                    if (value.isEmpty) {
                      return 'Insert something';
                    }
                    return null;
                  },
                ),
                FlatButton.icon(
                  icon: Icon(Icons.check),
                  label: Text('Done'),
                  onPressed: () {
                    _saveForm();
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

推荐阅读