Конструктор Виджета С Отслеживанием Состояния Flutter, Который Включает Не Все Элементы

#flutter #dart #constructor #statefulwidget

Вопрос:

Я создаю виджет с отслеживанием состояния в Flutter, и поэтому требуется, чтобы все аргументы, передаваемые в конструкторе, были окончательными (поскольку виджеты с отслеживанием состояния помечены аннотацией @immutable).

Дело в том, что я хочу иметь два разных конструктора для своего виджета и исключить некоторые элементы виджета с сохранением состояния, в зависимости от используемого конструктора. Я должен подчеркнуть, что я не хочу, чтобы эти аргументы были необязательными, но обязательными.

Например,

 class MyWidget extends StatefulWidget {
     
  MyWidget.first({this.firstArgument}};

  MyWidget.second({this.secondArgument});

  final int firstArgument;
  final String secondArgument;

  @override
  MyWidget createState() => MyWidgetState();
}
 

Когда я пишу это, я получаю ошибку компилятора, сообщающую мне, что:

Все конечные переменные должны быть инициализированы, но «Первый аргумент» — нет.

То же самое относится и ко второй переменной-члену.

Как я могу преодолеть это?

Я не могу переместить firstArgument и secondArgument в состояние MyWidget, так как я хочу, чтобы они были инициализированы в конструкторе(конструкторах), а также потому, что их не следует изменять. Я не могу пометить их как не окончательные, так как тогда я получу предупреждение компилятора, а также нарушу парадигму виджета с отслеживанием состояния.

Есть ли другой подход, который я должен использовать?

Ответ №1:

Дело в том, что я хочу иметь два разных конструктора для своего виджета и исключить некоторые элементы виджета с сохранением состояния, в зависимости от используемого конструктора. Я должен подчеркнуть, что я не хочу, чтобы эти аргументы были необязательными, но обязательными.

Если вы не хотите, чтобы они были необязательными, вам нужно пометить их как обязательные:

   MyWidget.first({required this.firstArgument}};

  MyWidget.second({required this.secondArgument});
 

(Если у вас не включена нулевая безопасность, вместо этого вам нужно будет использовать более слабую @required аннотацию из package:meta .)

Я понимаю, что вы хотите firstArgument , чтобы и secondArgument требовалось для MyWidget.first и MyWidget.second соответственно, но они не предназначены для того, чтобы требоваться вместе (то есть должен быть установлен только один).

Это можно исправить, явно инициализировав оба значения в конструкторах:

   MyWidget.first({required this.firstArgument}} : secondArgument = null;
  MyWidget.second({required this.secondArgument}): firstArgument = null;
 

Если у вас включена нулевая безопасность, вам также необходимо будет сделать своих участников недействительными:

   final int? firstArgument;
  final String? secondArgument;
 

Комментарии:

1. @jamesdiin — спасибо за подробный ответ. Не могли бы вы вкратце объяснить или указать место, где это делается, синтаксис конструктора, который вы предоставили, и его значение?

Ответ №2:

Может быть, заводские конструкторы помогут?

     class MyWidget extends StatefulWidget {
         
      MyWidget._({this.firstArgument, this.secondArgument}};
    
      factory MyWidget.first({@required int first})=>MyWidget._(firstArgument: first, );
      factory MyWidget.second({@required String second})=>MyWidget._(secondArgument: second, );
      final int firstArgument;
      final String secondArgument;
    
      @override
      MyWidget createState() => MyWidgetState();
    }

 

Таким образом, вы сможете создать этот виджет только с помощью этих конструкторов (поскольку конструктор класса является частным), и при вызове MyWidget.во-первых, значение secondArgument для виджета будет равно null, и то же самое применимо при использовании MyWidget.во-вторых, с помощью firstArgument

Комментарии:

1. Вы также можете использовать конструкторы перенаправления вместо конструкторов factory .