【问题标题】:Flutter - bottomModalSheet can't validate a textfield widgetFlutter - bottomModalSheet 无法验证文本字段小部件
【发布时间】:2022-11-14 09:43:39
【问题描述】:

我附上了一个具有底部模态表的项目。哪个表包含三个TextField 作为名称、号码和电子邮件。所以在这里我实现了 CRUD(创建、读取、更新和删除)操作,它工作正常。但在不验证TextField 的情况下,它会显示在HomePage 中。虽然如果我错过了输入姓名或号码,它仍然会将数据传递到主页卡。我尝试了许多验证选项,但没有成功。如果有人可以请帮助我。

我的代码:

import 'package:flutter/material.dart';


class HomePage extends StatefulWidget {
  const HomePage({super.key});


  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {



  List<Map<String, dynamic>> _contacts = [];

  bool _isLoading = true;
  final bool _validatename = true;
  final bool _validatenumber = true;
  final bool _validateemail = true;
  

    void _refreshContacts() async {
      final data = await Contact.getContacts();

      setState(() {
        _contacts  = data;
        _isLoading = false;
      });
    }

    @override
    void initState() {
      super.initState();
      _refreshContacts();
    }


    final  _nameController = TextEditingController();
    final  _numberController = TextEditingController();
    final  _emailController = TextEditingController();

    final bool _validate = false;


    void _showForm(int? id) async {
      if (id != null) {
        final existingContact = _contacts.firstWhere((element) => element['id'] ==id);
        _nameController.text = existingContact['name'];
        _numberController.text = existingContact['number'];
        _emailController.text = existingContact['email'];
      }

    showModalBottomSheet(context: context,
    elevation: 5,
    isScrollControlled: true,
     builder: (_) => Container(
      padding: EdgeInsets.only(top: 15, left: 15, right: 15, bottom: MediaQuery.of(context).viewInsets.bottom + 120),

      child:  Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.end,
        children: [
          TextField(
            controller: _nameController,
            decoration: const InputDecoration(
              hintText: "Name",
              ),
          ),
          const SizedBox(
            height: 10.0,
          ),
          TextField(
            keyboardType: TextInputType.number,
            controller: _numberController,
            decoration: const InputDecoration(
              hintText: "Numbers",
              ),
            
          ),
          const SizedBox(
            height: 10.0,
          ),
          TextField(
            // keyboardType: TextInputType.emailAddress,
            controller: _emailController,
            decoration: const InputDecoration(
              hintText: "Email Address",
              ),

          ),          
          const SizedBox(
            height: 20.0,
          ),

          Row(
            children: [
              ElevatedButton(
                onPressed:  () async {
                
                if (id == null) {
                  await _addContact();
                }

                if (id != null) {
                  await _updateContact(id);
                }




                Navigator.of(context).pop();

                _nameController.text = '';
                _numberController.text = '';
                _emailController.text = '';
              },

              
               child: Text(id == null ? 'Create New' : 'Update'),
               ),
               const SizedBox(
                width: 10.0,
               ),
              ElevatedButton(onPressed: () async {
                _nameController.text = '';
                _numberController.text = '';
                _emailController.text = '';
              }, child: const Text("Clear")),
              const SizedBox(
                width: 10.0,
               ),
              ElevatedButton(onPressed: (){
              Navigator.pop(context);

              }, child: const Text("Go Back")),
            ],
          ),


      ]),
      
     ));
      

    }

    Future<void> _addContact() async {
      await Contact.createContact(
        _nameController.text, _numberController.text, _emailController.text
      );
      _refreshContacts();
    }

    Future<void> _updateContact(int id) async {
      await Contact.updateContact(id, _nameController.text, _numberController.text, _emailController.text );

      _refreshContacts();
    }

    void _deleteContact(int id) async {
      await Contact.deleteContact(id);
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Sccessfully Contact Deleted")));
      _refreshContacts();
    }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Contact App",),
        backgroundColor: Colors.blueAccent,
        centerTitle: true,
        toolbarHeight: 80,
      ),
      body: _isLoading ? const Center(child: CircularProgressIndicator(),) : 
      ListView.builder(
        itemCount: _contacts.length,
        itemBuilder: (context, index) => 
          Card(
            elevation: 5,
            shape: const Border(
              right: BorderSide(color: Colors.blue, width: 10.0),
        
            ),
            color: Colors.orange[200],
            margin: const EdgeInsets.all(15.0),
            child: Material(
              elevation: 20.0,
              shadowColor: Colors.blueGrey,
              child: ListTile(
                title: Text(_contacts[index]['name'], style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),),
                subtitle: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(_contacts[index]['number'], style: const TextStyle(color: Colors.grey, fontSize: 18),),
                    const SizedBox(
                      height: 5.0,
                    ),
                    Text(_contacts[index]['email'], style: const TextStyle(fontSize: 17, color: Colors.black),),
                  ],
                ),
                trailing: SizedBox(
                  width: 100,
                  child: Row(
                    children: [
                      IconButton(onPressed: () => _showForm(_contacts[index]['id']), icon: const Icon(Icons.edit, color: Colors.blueGrey,)),
        
                      IconButton(onPressed: () => _deleteContact(_contacts[index]['id']), icon: const Icon(Icons.delete, color: Colors.red,)),

                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          child: const Icon(Icons.add, size: 28,),
          onPressed: () => _showForm(null), 
        ),
    );
  }


}

以上代码来自主页。我只需要验证部分 + 如果有人知道如何使用页面路由在另一个页面中显示每张卡片。实际上这是一个联系人应用程序。我已尝试使用新屏幕来显示全部详细信息,但无法显示。

【问题讨论】:

  • 看不到 validator 和表单小部件
  • 在“showModalBottomSheet”方法中,用“Form”小部件包装您的列并为其提供formkey,然后用“TextFormField”小部件替换“TextField”小部件,然后为每个小部件提供验证器属性。
  • 也尝试使用文本字段表单,但关键构造函数仍然没有成功。
  • 如果您在底部表格中有这么大的代码/小部件,那么最好的方法是在第二个 Statefull 小部件中执行代码,然后在底部表格中调用该小部件。

标签: flutter dart


【解决方案1】:

您可以在任何字段为空时返回,例如

ElevatedButton(
  onPressed: () async {
    if (_nameController.text.isEmpty ||
        _numberController.text.isEmpty ||
        _emailController.text.isEmpty) {
      return;
    }
  },
  child: Text(id == null ? 'Create New' : 'Update'),
),

但最好将 Form 小部件 TextFormFiled 与 validator 一起使用。在validation 上查找更多信息

final _formKey = GlobalKey<FormState>();
showModalBottomSheet(
  context: context,
  elevation: 5,
  isScrollControlled: true,
  builder: (_) => Container(
        child: Form(
          key: _formKey,
          child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                TextFormField(
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return 'Please enter some text';
                    }
                    return null;
                  },
                  controller: _nameController,
                  decoration: const InputDecoration(
                    hintText: "Name",
                  ),
                ),
                Row(
                  children: [
                    ElevatedButton(
                      onPressed: () async {
                        final isValided =
                            _formKey.currentState?.validate();

                        if (isValided == true) {}
                      },
                      child: Text(id == null ? 'Create New' : 'Update'),
                    ),

【讨论】:

  • 第一条评论会起作用吗?和文本字段表单我尝试了同样的事情。没用。如果你能实施吗?
  • 第一个会起作用,但不会有视觉效果,测试两者,看看哪种更适合你。另请检查链接以获取更多信息。
  • 不,第二个没用。验证器 obj 中的 value 参数是什么?我需要为此提供 _nameController 还是只留下价值?
  • 那是 Nullable 字符串,请确保添加所有验证器,但第一个建议是测试链接示例
  • 嘿,它起作用了,我只是注意到,当单击按钮时,它会显示错误消息,但仍会将其传递到屏幕。
猜你喜欢
  • 2019-04-24
  • 2020-02-13
  • 1970-01-01
  • 1970-01-01
  • 2015-09-04
  • 1970-01-01
  • 1970-01-01
  • 2020-12-11
  • 2020-11-28
相关资源
最近更新 更多