2

Im study flutter and i have a problem and I can't solve it. I'm trying to make a calculator based on some codes and this error appears

The method 'validate' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').

this is the code

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: Home()));
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  TextEditingController pesoController = TextEditingController();
  TextEditingController alturaController = TextEditingController();
  String _info = "Informe seus dados";
  GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  void _reset() {
    setState(() {
      pesoController.text = "";
      alturaController.text = "";
      _info = "Informe seus dados";
    });
  }

  void _calculate() {
    double peso = double.parse(pesoController.text);
    double altura = double.parse(alturaController.text) / 100;
    double imc = peso / (altura * altura);

    setState(() {
      if (imc < 18.6) {
        _info = "Abaixo do Peso (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 18.6 && imc <= 24.9) {
        _info = "Peso Ideal (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 24.9 && imc <= 29.9) {
        _info = "Levemente acima do peso (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 24.9 && imc <= 34.9) {
        _info = "Obesidade Grau I (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 34.9 && imc <= 39.9) {
        _info = "Obesidade Grau II (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 40) {
        _info = "Obesidade Grau III (${imc.toStringAsPrecision(2)})";
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Calculador IMC"),
        centerTitle: true,
        backgroundColor: Colors.deepPurple,
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: _reset,
          )
        ],
      ),
      backgroundColor: Colors.white,
      body: SingleChildScrollView(
        padding: EdgeInsets.all(20),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Icon(Icons.person, size: 120, color: Colors.deepPurple),
              TextFormField(
                keyboardType: TextInputType.number,
                decoration: InputDecoration(
                    labelText: "Peso (KG)",
                    labelStyle: TextStyle(color: Colors.deepPurple)),
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.deepPurple, fontSize: 25),
                controller: pesoController,
                validator: (value) {
                  if (value!.isEmpty) {
                    return "Informe seu peso!";
                  }
                },
              ),
              TextFormField(
                keyboardType: TextInputType.number,
                decoration: InputDecoration(
                    labelText: "Altura (CM)",
                    labelStyle: TextStyle(color: Colors.deepPurple)),
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.deepPurple, fontSize: 25),
                controller: alturaController,
                validator: (value) {
                  if (value!.isEmpty) {
                    return "Informe sua altura!";
                  }
                },
              ),
              Padding(
                  padding: EdgeInsets.fromLTRB(0.0, 15, 0.0, 15),
                  child: Container(
                    height: 50,
                    child: RaisedButton(
                      onPressed: () {
                        if (_formKey.currentState.validate()) {
                          _calculate();
                        }
                      },
                      child: Text(
                        "Calcular",
                        style: TextStyle(color: Colors.white, fontSize: 25),
                      ),
                      color: Colors.deepPurple,
                    ),
                  )),
              Text(_info,
                  textAlign: TextAlign.center,
                  style: TextStyle(color: Colors.deepPurple, fontSize: 25))
            ],
          ),
        ),
      ),
    );
  }
}

5 Answers5

17

The explanation is the following.

let's take into consideration the line on which this apply:

_formKey.currentState.validate()

the message

The method 'validate' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').

means that the property before "validate", so "currentState", could be null (https://dart.dev/null-safety for more info) in some cases.

In the cases it is actually null, you cannot call the "validate" method since null doesn't have a "validate" method. In other words, since doing this

null.validate()

is a no-go, calling "validate" method on something that is (or could only be, if you have the null safety active) null is a no-go either: dart is trying to tell you that you have to handle the case of a null value. Before the null-safety you could have written that and you could have found at runtime of this case.

In fact, at runtime "_formKey.currentState" could be an object as you would expect, but it could also be null in some specific cases. You have to decide how to handle that: are you 100% sure that in this case "_formKey.currentState" CAN'T ever be null? Or are you unsure?

At this point you have two options:

  1. use the "null assertion operator" (!.): telling by hand the compiler that calling "validate" method is completely safe at this point, for example, because you are already sure that even if the variable can theorically be null in some cases, you already checked it and that specific case is 100% safe. In other words, it will never be null in that specific point of your code. Be careful that, if you are wrong, it will throw an error at runtime (Null check operator used on a null value).
    _formKey.currentState!.validate();
  1. use the "null aware operator" (?.): you are unsure if in this case the currentState can be null. You are telling to your compiler to write this under the hood:
    if(_formKey.currentState != null) {
       _formKey.currentState.validate();
    }
Picchio
  • 425
  • 1
  • 7
6

Simply add '!' or '?' before .validate(). So change this line:

if (_formKey.currentState.validate()) {

to:

if (_formKey.currentState!.validate()) {

This is because of the null safety operators added to dart 2.0. You can read it more detailed in this link: https://dart.dev/null-safety

0

Try something like this:

validator: (value) {
    if (value!.length < 1) return 'Empty field';
    return null;
}
0

Try adding null safety before validate() method

0
 GlobalKey<FormState> _formKey = GlobalKey();
 TextButton(
                                  onPressed: () {
                                    if(_formKey.currentState!.validate()){
                                     ***code
                                    }
                                   
                                  },
                                  style: ButtonStyle(
                                    backgroundColor: MaterialStatePropertyAll(
                                        Colors.green.shade900),
                                  ),
                                  child: const Text(
                                    "Save",
                                    style: TextStyle(color: Colors.white),
                                  ),
                                ),
Use this one 
DevMukh
  • 1
  • 2