You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter表单提交报错:Null check operator used on a null value

Flutter表单提交出现Null check错误的解决方法

问题场景

在Flutter项目中使用控制器实现表单数据插入数据库功能,点击提交按钮时触发_CastError,提示“Null check operator used on a null value”。确认控制器已赋值,但尝试打印控制器值前就报错,怀疑问题出在提交回调或表单组件中,目标是实现表单数据成功插入数据库。

错误信息

处理手势时抛出以下_CastError:
Null check operator used on a null value

抛出异常时的调用栈:
#0      _FormPageState.build.<anonymous closure> (package:testerlogin/pages/formpage.dart:187:54)
#1      _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1072:21)
#2      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:253:24)
#3      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:627:11)
#4      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:306:5)
#5      BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:276:7)
#6      GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:163:27)
#7      GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:464:20)
#8      GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:440:22)
#9      RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:337:11)
#10     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:395:7)
#11     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:357:5)
#12     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:314:7)
#13     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:295:7)
#14     _invoke1 (dart:ui/hooks.dart:167:13)
#15     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:341:7)
#16     _dispatchPointerDataPacket (dart:ui/hooks.dart:94:31)

Handler: "onTap"
Recognizer:
  TapGestureRecognizer#75718

原始代码

import 'package:flutter/material.dart';
import 'package:testerlogin/models/flowerbook.dart';
import 'package:testerlogin/models/user.dart';
import '../common_widgets/buttons.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import '../common_widgets/checkbox.dart';

class FormPage extends StatefulWidget {
  const FormPage({Key? key, required this.user}) : super(key: key);
  final User user;
  @override
  State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
  final GlobalKey<FormBuilderState> _formKey = GlobalKey<FormBuilderState>();
  String selectedValue = 'Bouquet';

  final dateController = TextEditingController();
  final checkboxController = TextEditingController();
  final dropdownController = TextEditingController();

  final TextStyle labelStyle = const TextStyle(
    fontFamily: 'Poppins',
    fontWeight: FontWeight.w500,
  );

  final TextStyle inputStyle = const TextStyle(
    fontFamily: 'Poppins',
    fontWeight: FontWeight.w600,
  );

  @override
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      body: SingleChildScrollView(
        child: Form(
          key: _formKey,
          child: SafeArea(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                //Spacing
                const SizedBox(
                  height: 25,
                ),

                //Back Button
                Container(
                  height: 50,
                  padding: const EdgeInsets.fromLTRB(2 * 16, 0, 2 * 16, 0),
                  width: double.infinity,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      IconButton(
                        onPressed: () {
                          Navigator.pop(context);
                        },
                        icon: const Icon(Icons.arrow_back),
                      ),
                    ],
                  ),
                ),

                const SizedBox(
                  height: 25,
                ),

                SizedBox(
                  width: screenWidth,
                  child: Padding(
                    padding:
                        const EdgeInsets.fromLTRB(3 * 16, 0, 3 * 16, 3 * 16),
                    child: Column(
                      children: [
                        //Checkbox

                        FormField(builder: (FormFieldState state) {
                          return InputDecorator(
                              decoration: InputDecoration(
                                labelText: "Delivery Date",
                                labelStyle: labelStyle,
                                errorText: state.errorText,
                                border: const OutlineInputBorder(),
                                floatingLabelBehavior:
                                    FloatingLabelBehavior.always,
                              ),
                              child: FormBuilderDateTimePicker(
                                controller: dateController,
                                name: "delivery_date",
                              ));
                        }),

                        const SizedBox(height: 25),

                        FormField(
                          builder: (FormFieldState state) {
                            return InputDecorator(
                              decoration: InputDecoration(
                                labelText: "Flower Type",
                                labelStyle: labelStyle,
                                errorText: state.errorText,
                                border: const OutlineInputBorder(),
                                floatingLabelBehavior:
                                    FloatingLabelBehavior.always,
                              ),
                              child: Column(
                                children: <Widget>[
                                  checkItemBuilder(context, "Roses",
                                      checkboxController: checkboxController),
                                  checkItemBuilder(context, "Tulips",
                                      checkboxController: checkboxController),
                                  checkItemBuilder(context, "Carnation",
                                      checkboxController: checkboxController),
                                  checkItemBuilder(context, "Daisies",
                                      checkboxController: checkboxController),
                                  checkItemBuilder(context, "Tulips",
                                      checkboxController: checkboxController),
                                ],
                              ),
                            );
                          },
                        ),

                        const SizedBox(height: 25),

                        SizedBox(
                          width: MediaQuery.of(context).size.width,
                          child: FormField(
                            builder: (FormFieldState state) {
                              return InputDecorator(
                                decoration: InputDecoration(
                                  labelText: "Arrangement",
                                  labelStyle: labelStyle,
                                  errorText: state.errorText,
                                  border: const OutlineInputBorder(),
                                  floatingLabelBehavior:
                                      FloatingLabelBehavior.always,
                                ),
                                child: DropdownButton<String>(
                                  value: selectedValue,
                                  isExpanded: true,
                                  onChanged: (String? newValue) {
                                    setState(() {
                                      selectedValue = newValue ?? 'Bouquet';
                                      dropdownController.text = selectedValue;
                                    });
                                  },
                                  items: <String>[
                                    'Bouquet',
                                    'Vase',
                                    'Box',
                                    'Basket'
                                  ].map<DropdownMenuItem<String>>(
                                      (String value) {
                                    return DropdownMenuItem<String>(
                                      value: value,
                                      child: Text(value),
                                    );
                                  }).toList(),
                                ),
                              );
                            },
                          ),
                        ),

                        const SizedBox(height: 25),

                        //Submit Button
                        ButtonGradient(
                          label: 'Submit',
                          textStyle: const TextStyle(
                            fontFamily: 'Poppins',
                            fontWeight: FontWeight.w600,
                            color: Colors.white,
                          ),
                          borderRadius: 50,
                          gradientColor: const [
                            Colors.purpleAccent,
                            Colors.deepPurple,
                          ],
                          onPressed: () {
                            if (_formKey.currentState!.validate()) {
                              Flowerbook flowerbook = Flowerbook(
                                deliver_date: dateController.text,
                                flower_type: checkboxController.text,
                                arrangement: dropdownController.text,
                                user_id: widget.user.user_id,
                              );

                              Flowerbook.register(flowerbook);
                            }
                          },
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

问题分析

  1. 表单Key类型不匹配:代码中定义的_formKey是GlobalKey<FormBuilderState>,但实际使用的是Flutter原生的Form组件,而非FormBuilder组件,导致_formKey.currentState为null,使用!空检查运算符时触发错误。
  2. FormField未实现验证逻辑:所有自定义的FormField都没有提供validator回调,导致validate()方法无法正常工作,也无法触发表单验证。
  3. FormBuilder组件与原生Form混用:使用了FormBuilderDateTimePicker但外层是原生Form,组件间不兼容,无法正常关联表单状态。

解决方案

方案1:使用原生Form组件(修正Key类型)

将_formKey的类型改为GlobalKey<FormState>,并为每个FormField添加验证逻辑:

class _FormPageState extends State<FormPage> {
  // 修正为FormState的Key
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  String selectedValue = 'Bouquet';

  final dateController = TextEditingController();
  final checkboxController = TextEditingController();
  final dropdownController = TextEditingController();

  // ... 其他代码不变

  @override
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      body: SingleChildScrollView(
        child: Form(
          key: _formKey,
          child: SafeArea(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // ... 其他代码不变

                // 修正Delivery Date的FormField,添加验证
                FormField<String>(
                  validator: (value) {
                    if (dateController.text.isEmpty) {
                      return '请选择配送日期';
                    }
                    return null;
                  },
                  builder: (FormFieldState<String> state) {
                    return InputDecorator(
                        decoration: InputDecoration(
                          labelText: "Delivery Date",
                          labelStyle: labelStyle,
                          errorText: state.errorText,
                          border: const OutlineInputBorder(),
                          floatingLabelBehavior: FloatingLabelBehavior.always,
                        ),
                        // 替换为原生DateTimePicker,避免FormBuilder组件冲突
                        child: TextField(
                          controller: dateController,
                          readOnly: true,
                          onTap: () async {
                            DateTime? pickedDate = await showDatePicker(
                              context: context,
                              initialDate: DateTime.now(),
                              firstDate: DateTime(2000),
                              lastDate: DateTime(2101),
                            );
                            if (pickedDate != null) {
                              setState(() {
                                dateController.text = "${pickedDate.day}/${pickedDate.month}/${pickedDate.year}";
                              });
                            }
                          },
                        ));
                  },
                ),

                const SizedBox(height: 25),

                // 修正Flower Type的FormField,添加验证
                FormField<String>(
                  validator: (value) {
                    if (checkboxController.text.isEmpty) {
                      return '请选择至少一种花卉类型';
                    }
                    return null;
                  },
                  builder: (FormFieldState<String> state) {
                    return InputDecorator(
                      decoration: InputDecoration(
                        labelText: "Flower Type",
                        labelStyle: labelStyle,
                        errorText: state.errorText,
                        border: const OutlineInputBorder(),
                        floatingLabelBehavior: FloatingLabelBehavior.always,
                      ),
                      child: Column(
                        children: <Widget>[
                          checkItemBuilder(context, "Roses", checkboxController: checkboxController),
                          checkItemBuilder(context, "Tulips", checkboxController: checkboxController),
                          checkItemBuilder(context, "Carnation", checkboxController: checkboxController),
                          checkItemBuilder(context, "Daisies", checkboxController: checkboxController),
                        ],
                      ),
                    );
                  },
                ),

                const SizedBox(height: 25),

                // 修正Arrangement的FormField,添加验证
                FormField<String>(
                  validator: (value) {
                    if (dropdownController.text.isEmpty) {
                      return '请选择花束类型';
                    }
                    return null;
                  },
                  builder: (FormFieldState<String> state) {
                    return InputDecorator(
                      decoration: InputDecoration(
                        labelText: "Arrangement",
                        labelStyle: labelStyle,
                        errorText: state.errorText,
                        border: const OutlineInputBorder(),
                        floatingLabelBehavior: FloatingLabelBehavior.always,
                      ),
                      child: DropdownButton<String>(
                        value: selectedValue,
                        isExpanded: true,
                        onChanged: (String? newValue) {
                          setState(() {
                            selectedValue = newValue ?? 'Bouquet';
                            dropdownController.text = selectedValue;
                          });
                        },
                        items: <String>[
                          'Bouquet', 'Vase', 'Box', 'Basket'
                        ].map<DropdownMenuItem<String>>((String value) {
                          return DropdownMenuItem<String>(
                            value: value,
                            child: Text(value),
                          );
                        }).toList(),
                      ),
                    );
                  },
                ),

                const SizedBox(height: 25),

                //Submit Button
                ButtonGradient(
                  label: 'Submit',
                  textStyle: const TextStyle(
                    fontFamily: 'Poppins',
                    fontWeight: FontWeight.w600,
                    color: Colors.white,
                  ),
                  borderRadius: 50,
                  gradientColor: const [
                    Colors.purpleAccent,
                    Colors.deepPurple,
                  ],
                  onPressed: () {
                    // 先检查formKey是否存在,避免空值
                    if (_formKey.currentState != null && _formKey.currentState!.validate()) {
                      Flowerbook flowerbook = Flowerbook(
                        deliver_date: dateController.text,
                        flower_type: checkboxController.text,
                        arrangement: dropdownController.text,
                        user_id: widget.user.user_id ?? 0, // 处理user_id可能为null的情况
                      );

                      Flowerbook.register(flowerbook);
                      // 提交成功后可以添加提示或跳转
                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text('提交成功')),
                      );
                    }
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

方案2:使用FormBuilder组件(保持Key类型)

如果要继续使用FormBuilder组件,需要将外层的Form替换为FormBuilder,并调整组件用法:

class _FormPageState extends State<FormPage> {
  final GlobalKey<FormBuilderState> _formKey = GlobalKey<FormBuilderState>();
  String selectedValue = 'Bouquet';

  // 可以不需要单独的控制器,FormBuilder会自动管理状态
  final checkboxController = TextEditingController();

  // ... 其他代码不变

  @override
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      body: SingleChildScrollView(
        // 替换为FormBuilder
        child: FormBuilder(
          key: _formKey,
          child: SafeArea(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // ... 其他代码不变

                // 使用FormBuilderDateTimePicker
                FormBuilderDateTimePicker(
                  name: "delivery_date",
                  decoration: InputDecoration(
                    labelText: "Delivery Date",
                    labelStyle: labelStyle,
                    border: const OutlineInputBorder(),
                    floatingLabelBehavior: FloatingLabelBehavior.always,
                  ),
                  inputType: InputType.date,
                ),

                const SizedBox(height: 25),

                // 花卉类型可以用FormBuilderCheckboxGroup
                FormBuilderCheckboxGroup(
                  name: "flower_type",
                  decoration: InputDecoration(
                    labelText: "Flower Type",
                    labelStyle: labelStyle,
                    border: const OutlineInputBorder(),
                    floatingLabelBehavior: FloatingLabelBehavior.always,
                  ),
                  options: const [
                    FormBuilderFieldOption(value: "Roses"),
                    FormBuilderFieldOption(value: "Tulips"),
                    FormBuilderFieldOption(value: "Carnation"),
                    FormBuilderFieldOption(value: "Daisies"),
                  ],
                ),

                const SizedBox(height: 25),

                // 使用FormBuilderDropdown
                FormBuilderDropdown(
                  name: "arrangement",
                  decoration: InputDecoration(
                    labelText: "Arrangement",
                    labelStyle: labelStyle,
                    border: const OutlineInputBorder(),
                    floatingLabelBehavior: FloatingLabelBehavior.always,
                  ),
                  initialValue: 'Bouquet',
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:50:23