Flutter:当字段在 ListView 中不可见时,不会调用 TextFormField 验证器

dav*_*ode 7 dart flutter

我在这个问题上也遇到了同样的问题,我通过遵循提供的建议解决了(我setState()在 中调用onChanged)...问题是,在我的情况下validator,如果该字段在视图中不可见(如果您滚动视图直到它不再显示),这样我就可以在无效状态下提交表单。

我应该如何触发当前未显示在 中的字段的验证ListView

更新:

以下是该问题的简单演示(我使用它在一个独立的简单应用程序中进行调试):

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyForm extends StatefulWidget {
  @override
  State createState() {
    return _MyFormState();
  }
}

class _MyFormState extends State<MyForm> {
  static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final Map<int, String> model = Map<int, String>();

  @override
  void initState() {
    print('initState()');
    for (int i = 0; i < 20; i++) {
      model[i] = null;
    }
    super.initState();
  }

  String validate(String value) {
    return value.isEmpty ? 'Cannot be blank!' : null;
  }

  void submitForm() {
    final FormState formState = _formKey.currentState;

    if (formState.validate()) {
      print('form is valid');
      formState.save();
    } else {
      print('form is invalid');
    }
  }

  @override
  Widget build(BuildContext context) {
    List<Widget> fields = [];

    for (int i = 0; i < 20; i++) {
      Widget widget = TextFormField(
        initialValue: model[i],
        decoration: InputDecoration(
          labelText: 'field $i',
        ),
        validator: validate,
        onFieldSubmitted: (String value) {
          print('field $i onFieldSubmitted()');
          setState(() {
            model[i] = value;
          });
        },
        onChanged: (String value) {
          print('field $i onChanged()');
          setState(() {
            model[i] = value;
          });
        },
        onSaved: (String value) {
          print('field $i onSaved()');
          setState(() {
            model[i] = value;
          });
        },
      );
      fields.add(widget);
    }

    fields.add(RaisedButton(
      child: Text('save'),
      onPressed: submitForm,
    ));

    return Form(
      key: _formKey,
      child: ListView(
        children: fields,
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('form test'),
        ),
        body: MyForm(),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

dav*_*ode 9

解决方案很简单,只是不使用ListView而是依赖SingleChildScrollView(并将表单本身作为子项传递)

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyForm extends StatefulWidget {
  @override
  State createState() {
    return _MyFormState();
  }
}

class _MyFormState extends State<MyForm> {
  static final GlobalKey<FormState> _formKey = GlobalKey();

  final Map<int, String> model = Map<int, String>();

  @override
  void initState() {
    print('initState()');
    for (int i = 0; i < 20; i++) {
      model[i] = null;
    }
    super.initState();
  }

  String validate(String value) {
    return value.isEmpty ? 'Cannot be blank!' : null;
  }

  void submitForm() {
    final FormState formState = _formKey.currentState;

    if (formState.validate()) {
      print('form is valid');
      formState.save();
    } else {
      print('form is invalid');
    }
  }

  @override
  Widget build(BuildContext context) {
    List<Widget> fields = [];

    for (int i = 0; i < 20; i++) {
      Widget widget = TextFormField(
        initialValue: model[i],
        decoration: InputDecoration(
          labelText: 'field $i',
        ),
        validator: validate,
        onFieldSubmitted: (String value) {
          print('field $i onFieldSubmitted()');
          setState(() {
            model[i] = value;
          });
        },
      );
      fields.add(widget);
    }

    fields.add(RaisedButton(
      child: Text('save'),
      onPressed: submitForm,
    ));

    return SingleChildScrollView(
      child: Form(
        key: _formKey,
        child: Column(
          children: fields,
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('form test'),
        ),
        body: MyForm(),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)