web-dev-qa-db-fra.com

Erreur: seuls les membres statiques sont accessibles dans les initialiseurs. Qu'est-ce que cela signifie?

J'ai quelque chose comme ça. J'ai du mal à comprendre cette erreur. Pourquoi accéder à filterController ici donne-t-il cette erreur ici? mais cela ne donne pas cette erreur si je déplace l'ensemble de la création actuelle TextFormField (entre les commentaires A et B) à l'intérieur de la méthode de construction? Comment le déplacement de l'intégralité de TextFormField à l'intérieur de la méthode de génération rend-il filterController statique alors et résout-il ce problème?

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin
{

    TabController _tabController;
    final filterController = new TextEditingController(text: "Search");
        //----A
        TextFormField email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: filterController,    ------>ERROR : Error: Only static members can be accessed in initializers
        );
       //----B

  @override
    Widget build(BuildContext context)
    {
        return new Scaffold(
                appBar: new AppBar(..),
        );
    }
}

Comment puis-je résoudre ce problème?

20
MistyD
class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {

    TabController _tabController;
    final filterController = new TextEditingController(text: "Search");
    TextFormField email = ...

... est un initialiseur et il n’ya aucun moyen d’accéder à this à ce stade. Les initialiseurs sont exécutés avant le constructeur, mais l'accès à this est autorisé uniquement après la fin de l'appel du super constructeur (implicite dans votre exemple). Par conséquent, seul le corps du constructeur (ou une version ultérieure) permet l’accès à this.

C'est pourquoi vous obtenez le message d'erreur:

controller: filterController,

accès this.filterController (this est implicite si vous ne l'écrivez pas explicitement).

Pour contourner votre problème (en supposant que email doit être final), vous pouvez utiliser un constructeur de fabrique et une liste d'initialiseurs de constructeur:

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {
  factory SingleTickerProviderStateMixin() => 
      new SingleTickerProviderStateMixin._(new TextEditingController(text: "Search"));

  SingleTickerProviderStateMixin._(TextEditingController textEditingController) : 
      this.filterController = textEditingController,   
      this.email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: textEditingController);

  TabController _tabController;
  final filterController;
  final TextFormField email;

ou lorsque le champ email n'a pas besoin d'être définitif, email peut être initialisé dans la liste d'initialisation du constructeur:

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {

  SingleTickerProviderStateMixin() {
    email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: filterController,
    );
  }

  TabController _tabController;
  final filterController = new TextEditingController(text: "Search");
  TextFormField email;

mais dans les widgets Flutter initState est généralement utilisé pour cela

class AppHomeState extends State<AppHome> with SingleTickerProviderStateMixin {

  @override
  void initState() {
    super.initState();
    email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: filterController,
    );
  }

  TabController _tabController;
  final filterController = new TextEditingController(text: "Search");
  TextFormField email; 
28

Vous pouvez garder cela comme méthode:

Widget getEmailController(){
return new
 TextFormField email = new TextFormField(
        keyboardType: TextInputType.emailAddress,
        controller: filterController,
        );
}

et l'utiliser dans l'interface utilisateur:

body: Container(
child: getEmailController();
)
2
Ruben Martirosyan

Vous pouvez convertir cette variable en une fonction et prendre contexte dans les paramètres de cette fonction.

Exemple

Widget myDialog (BuildContext context) {
  return new Scaffold(
    backgroundColor: Colors.white,
    body: new Center(
      child: new Column(
        children: <Widget>[
          new Text("Invalid Username/Password"),
          new Text("Please verify your login credentials"),
          new RaisedButton(
            child: new Text("Ok"),
            onPressed:() {
              Navigator.pop(context);//Error : Only static members can be accessed in initializers
            }
          ),
        ],
      ),
    )
  );
}

// Using if you are doing in a class
this.myDialog(context);

// Using if you are using a global function
myDialog(context);

Mais je pense que vous voulez afficher un message d'erreur. Donc, vous pouvez le faire avec un dialogue et non une page. C'est plus efficace car vous pouvez spécifier votre boîte de dialogue avec des boutons ou des messages et vous pouvez utiliser cette boîte de dialogue d'erreur partout. Regardons ma fonction d'assistance globale pour afficher les messages d'erreur.

void showError(BuildContext context, String error) {
  showSnackBar(
    context,
    new Text(
      'Error',
      style: new TextStyle(color: Theme.of(context).errorColor),
    ),
    content: new SingleChildScrollView(
      child: new Text(error)
    ),
    actions: <Widget>[
      new FlatButton(
        child: new Text(
          'Ok',
          style: new TextStyle(
            color: Colors.white
          ),
        ),
        onPressed: () {
          Navigator.of(context).pop();
        },
        color: Theme.of(context).errorColor,
      ),
    ]
  );
}

// Using in everywhere
showError(context, 'Sample Error');
0
Anilcan