Skip to content

Latest commit

 

History

History
382 lines (297 loc) · 12.2 KB

README_RU.md

File metadata and controls

382 lines (297 loc) · 12.2 KB

Property and Commands for ChangeNotifier

ссылка на пакет pub.dev

Пакет содержит следующие декарирующие классы: Property<T>, Command, ParameterizedCommand<T>, AsyncCommand, ParameterizedAsyncCommand<T>. Данные классы могут быть полезны при создании въюмоделей на основе классов расширяющих ChangeNotifier.

Пример №1

Работа примера

В классе въюмодели class FirstPageNotifier extends ChangeNotifier определены свойство и команды.

Свойство

Для хранения значения счетчика

late final outputProperty = Property<int>(
    initialValue: 0,
    notifyListeners: notifyListeners,
);

Задано начальное значение свойства и вызов метода notifyListeners() в случае изменения значения данного свойства.

В методе build(BuildContext context) класса FirstPage extends StatelessWidget получаем отслеживаемую ссылку на значение свойства

final output =
    FirstPageInheritedNotifier.watchNotifier(context).outputProperty.value;
```,

вывод значения осуществляется следующим образом

```dart
Text(
    output.toString(),
    style: Theme.of(context).textTheme.headlineLarge,
),

Команды

Для инкремента и декремента счетчика созданы две команды

late final incrementCommand = Command(
    action: () => outputProperty.value += 1,
    canAction: () => outputProperty.value < 3,
  );

  late final decrementCommand = Command(
    action: () => outputProperty.value -= 1,
    canAction: () => outputProperty.value > 0,
  );

В качестве аргументов для параметра action передаются методы изменяющие значение свойства счетчика. В качестве аргументов для параметра canAction, который ограничивает доступность команды на выполнение, передаются методы ограничивающие диапозон значений счетчика.

В классе FirstPage в методе build(BuildContext context) получаем ссылки на команды

final incrementCommand =
    FirstPageInheritedNotifier.readNotifier(context).incrementCommand;
final decrementCommand =
    FirstPageInheritedNotifier.readNotifier(context).decrementCommand;

Использование команд для работы кнопок

ElevatedButton(
    onPressed: decrementCommand.canExecute()
        ? decrementCommand.execute
        : null,
    child: const Icon(Icons.exposure_minus_1),
),

и

ElevatedButton(
    onPressed: incrementCommand.canExecute()
        ? incrementCommand.execute
        : null,
    child: const Icon(Icons.plus_one),
),

Можно видеть, что в методе параметра onPressed происходит проверка возможности выполнения команды, что влияет на доступность кнопки для клика.

Пример №2

Работа примера

В классе въюмодели SecondPageNotifier extends ChangeNotifier определены свойство и команда.

Свойство

Для отображения значения счетчика определено одно свойство, которое задано только своим начальным значением.

final outputProperty = Property<int>(initialValue: 0);

В классе SecondPage в методе build(BuildContext context) получаем отслеживаемую ссылку на значение свойства

final output =
    SecondPageInheritedNotifier.watchNotifier(context).outputProperty.value;

Отображение значения свойства

Text(
    output.toString(),
    style: Theme.of(context).textTheme.headlineLarge,
),

Команда

Для кнопок опредена одна общая параметризованная команда, которая при вызове на выполнение в качестве аргумента принимает int величину.

late final changeCommand = ParameterizedCommand<int>(
    action: (value) => outputProperty.value += value,
    notifyListeners: notifyListeners,
);

При выполнении метода команды происходит вызов notifyListeners().

В классе SecondPage в методе build(BuildContext context) получаем ссылку на команду

final command =
        SecondPageInheritedNotifier.readNotifier(context).changeCommand;

Использование команды для кнопок выглядит следующим образом

ElevatedButton(
    onPressed: () => command(-1),
    child: Text(
        '-1',
        style: Theme.of(context).textTheme.titleLarge,
    ),
),

...

ElevatedButton(
    onPressed: () => command(3),
    child: Text(
        '3',
        style: Theme.of(context).textTheme.titleLarge,
    ),
),

Пример №3

Работа примера

В классе въюмодели ThirdPageNotifier extends ChangeNotifier определены три свойства и команда.

Свойства

Для CheckboxListTile задано свойство с вызовом notifyListeners().

late final isEnabledProperty = Property<bool>(
    initialValue: false,
    notifyListeners: notifyListeners,
);
```.

Далее в `_ThirdPageState` получаем отслеживаемую ссылку на это свойство

```dart
final isEnabledProperty =
    ThirdPageInheritedNotifier.watchNotifier(context).isEnabledProperty;

и используем таким образом

CheckboxListTile(
    title: const Text('enable the input line'),
    controlAffinity: ListTileControlAffinity.platform,
    contentPadding: const EdgeInsets.all(50),
    value: isEnabledProperty.value,
    onChanged: (value) {
        isEnabledProperty.value = value!;
    },
),

Для TextField задано свойство с вызовом notifyListeners() и правилами верификации.

late final inputProperty = Property<String>(
    initialValue: '',
    notifyListeners: notifyListeners,
    verificationRules: <String, bool Function(String)>{
      'The value cannot be an empty string': (value) => value.isEmpty,
      'The length of the string cannot be less than 3 characters': (value) =>
          value.length < 3,
    },
);

Для правила верификации в качестве ключа указывается текстовое сообщение для пользователя, а в качестве значения метод возвращающий true.

В InputTextWidget получем ссылки на свойства

final isEnabledProperty =
        ThirdPageInheritedNotifier.watchNotifier(context).isEnabledProperty;
final inputProperty =
    ThirdPageInheritedNotifier.readNotifier(context).inputProperty;

и используем таким образом

TextField(
    decoration: InputDecoration(
        border: const OutlineInputBorder(),
        labelText: 'Enter the Value',
        errorText: inputProperty.hasErrors ? inputProperty.errors[0] : null,
    ),
    enabled: isEnabledProperty.value,
    controller: controller,
    onChanged: (text) {
        inputProperty.value = text;
    },
),

В этой строке errorText: inputProperty.hasErrors ? inputProperty.errors[0] : null, определена логика отображения сообщений пользователю об ошибке при вводе данных.

Доступность TextField для ввода привязана к значению CheckboxListTile через свойство isEnabledProperty в этой строке enabled: isEnabledProperty.value,.

Свойство inputProperty обновляет свое значение в методе определенном для onChanged.

Для вывода результата используется простое свойство final outputProperty = Property<String>(initialValue: '');.

Команда

В примере используется одна асинхронная команда для кнопки

late final submitCommand = AsyncCommand(
    action: () async {
      await Future.delayed(const Duration(milliseconds: 100));
      outputProperty.value = inputProperty.value;
      inputProperty.value = '';
      isEnabledProperty.value = false;
    },
    canAction: () => inputProperty.hasErrors == false,
    notifyListeners: notifyListeners,
);

Доступность кнопки зависит от наличия ошибок при вводе с помощью параметра canAction: () => inputProperty.hasErrors == false,.

При выполнении метода команды происходит вызов notifyListeners().

В _ThirdPageState получаем ссылку на команду

final submitCommand =
    ThirdPageInheritedNotifier.readNotifier(context).submitCommand;

и используем команду для кнопки таким образом.

ElevatedButton(
    onPressed: submitCommand.canExecute()
        ? (() async {
            await submitCommand.execute();
            controller.clear();
        })
        : null,
    child: const Icon(Icons.done),
),

Пример №4

Работа примера

В классе въюмодели FourthPageNotifier extends ChangeNotifier определены одно свойство и три команды.

Свойство

Для отображения списка создано свойство.

final peopleProperty = Property<List<Person>>(
    initialValue: <Person>[],
);

В PeopleListViewWidget получаем отслеживаемую ссылку на свойство.

final people =
    FourthPageInheritedNotifier.watchNotifier(context).peopleProperty.value;

Отображение коллекции людей с помощью ListView.builder() и ListTile.

ListView.builder(
    itemCount: people.length,
    itemBuilder: (context, index) {
        final person = people[index];
        return ListTile(
            onTap: () async {...},
            title: Text(person.fullName),
            subtitle: Text('ID: ${person.id}'),
            trailing: TextButton(...),
        );
    },
),

Команды

Для реализации CRUD операций над коллекцией людей созданы три параметризованных асинхронных команды: addCommand, removeCommand, updateCommand.

Пример на addCommand.

late final addCommand = ParameterizedAsyncCommand<List<String>>(
    action: (value) async {
      await _db.create(names: value);
      peopleProperty.value = await _db.getPeople();
    },
    notifyListeners: notifyListeners,
);

В ComposeWidget в методе Widget build(BuildContext context) получаем ссылку на команду.

final command =
    FourthPageInheritedNotifier.readNotifier(context).addCommand;

Используем команду таким образом

TextButton(
    onPressed: () async {
        final names = <String>[
            firstNameController.text,
            lastNameController.text,
        ];
        await command(names);
        firstNameController.clear();
        lastNameController.clear();
    },
    child: Text(
    'Add to list',
    style: Theme.of(context).textTheme.titleMedium,
))