Как исправить _TypeError (тип 'List<Animal?>' не является подтипом типа 'List<Animal>?' значения 'value')

Я не могу понять, что не так с моим кодом. Что бы я ни пытался, я все равно получаю эту ошибку при попытке подтвердить свой выбор в виджете с множественным выбором. Вот мой код.

class _ParticipantsToSelectState extends State<ParticipantsToSelect> {
  static List<Animal> _animals = [
    Animal(id: 1, name: "Lion"),
    Animal(id: 2, name: "Flamingo"),
    Animal(id: 3, name: "Hippo"),
    Animal(id: 4, name: "Horse"),
    Animal(id: 5, name: "Tiger"),
    Animal(id: 6, name: "Penguin"),
    Animal(id: 7, name: "Spider"),
    Animal(id: 8, name: "Snake"),
    Animal(id: 9, name: "Bear"),
    Animal(id: 10, name: "Beaver"),
  ];

  final _items = _animals
      .map((animal) => MultiSelectItem<Animal>(animal, animal.name))
      .toList();
  List<Animal?>? _selectedAnimals3 = [];
  final _multiSelectKey = GlobalKey<FormFieldState<List<Animal>?>>(); // Update here

  @override
  void initState() {
    _selectedAnimals3 = _animals;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: MultiSelectBottomSheetField<Animal>(
        key: _multiSelectKey,
        initialChildSize: 0.7,
        maxChildSize: 0.95,
        title: Text("Animals"),
        buttonText: Text("Favorite Animals"),
        items: _items,
        searchable: true,
        validator: (values) {
          if (values == null || values.isEmpty) {
            return "Required";
          }
          List<String> names = values.map((e) => e!.name).toList(); // Update here
          if (names.contains("Frog")) {
            return "Frogs are weird!";
          }
          return null;
        },
        onConfirm: (List<Animal?>? values) { // Update here
          setState(() {
            _selectedAnimals3 = values;
          });
          _multiSelectKey.currentState?.validate();
        },
        chipDisplay: MultiSelectChipDisplay(
          onTap: (item) {
            setState(() {
              _selectedAnimals3!.remove(item);
            });
            _multiSelectKey.currentState?.validate();
          },
        ),
      ),
    );
  }
}

Я попытался передать _selectedAnimals3, а также «значения», а затем инициализировать его с помощью _animals, но получил ту же ошибку. Мне нужно, чтобы _selectedAnimals3 заполнялся выбранными элементами при подтверждении.

Позвольте спросить вас, как вы думаете, в чем разница между List<Animal?> и List<Animal>??

Dai 18.02.2023 23:10

Кроме того, почему вы объявили _selectedAnimals3 ссылкой, допускающей значение NULL? Он инициализируется ненулевым значением, и вашему методу onConfirm не нужно заменять всю коллекцию, вы можете просто очистить ее.

Dai 18.02.2023 23:14

Итак, List<Animal?> означает список объектов типа Animal, которые могут иметь нулевые значения, тогда как List<Animal>? означает допускающий значение NULL список объектов типа Animal, который может быть либо списком объектов типа Animal, либо нулевым значением.

martin sanzoo 18.02.2023 23:15

Хорошо, так почему вы говорите, что не понимаете, что не так с вашим кодом?

Dai 18.02.2023 23:18

На самом деле я начал с List<Animal> _selectedAnimals3 = []; и я думаю, что это было неправильно? Можете ли вы предложить, какие должны быть строки для объявления и onConfirm ?

martin sanzoo 18.02.2023 23:21

Это было мое начальное объявление и onConfirm, которые выдавали ту же ошибку. List<Animal> _selectedAnimals3 = []; onConfirm: (значения) { setState(() { _selectedAnimals3 = values ​​.where((element) => element != null) .toList() .cast<Animal>(); }); _multiSelectKey.currentState?.validate(); },

martin sanzoo 18.02.2023 23:26

Вашему методу onConfirm не нужно перезаписывать _selectedAnimals3 в аргументах null — просто очистите существующий список, если values равно null.

Dai 18.02.2023 23:28

Спасибо за быстрый ответ, но не могли бы вы предложить код для очистки существующего списка?

martin sanzoo 18.02.2023 23:39

Э... .clear() ?

Dai 18.02.2023 23:48

Извините, я не понимаю. Если я использую clear(), он очистит весь список, не так ли? Я хочу, чтобы _selectedAnimals3 сохранял выбранные элементы.

martin sanzoo 19.02.2023 00:07

Так что же тогда onConfirm должно быть связано с values?

Dai 19.02.2023 00:07

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

martin sanzoo 19.02.2023 00:28
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Типы ввода HTML: Лучшие практики и советы
Типы ввода HTML: Лучшие практики и советы
HTML, или HyperText Markup Language , является стандартным языком разметки, используемым для создания веб-страниц. Типы ввода HTML - это различные...
Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений
Услуги PHP-разработки могут быть экономически эффективным решением для компаний, которые ищут высококачественные услуги веб-разработки по доступным...
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
Слишком много useState? Давайте useReducer!
Слишком много useState? Давайте useReducer!
Современный фронтенд похож на старую добрую веб-разработку, но с одной загвоздкой: страница в браузере так же сложна, как и бэкенд.
Узнайте, как использовать теги &lt;ul&gt; и &lt;li&gt; для создания неупорядоченных списков в HTML
Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML
HTML предоставляет множество тегов для структурирования и организации содержимого веб-страницы. Одним из наиболее часто используемых тегов для...
1
12
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это давно известная проблема в этой библиотеке, чтобы избежать этой проблемы, вы должны сделать параметр типа MultiSelectBottomSheetField<Animal?> обнуляемым.

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

class _ParticipantsToSelectState extends State<ParticipantsToSelect> {
  static final List<Animal> _animals = [
    Animal(id: 1, name: "Lion"),
    Animal(id: 2, name: "Flamingo"),
    Animal(id: 3, name: "Hippo"),
    Animal(id: 4, name: "Horse"),
    Animal(id: 5, name: "Tiger"),
    Animal(id: 6, name: "Penguin"),
    Animal(id: 7, name: "Spider"),
    Animal(id: 8, name: "Snake"),
    Animal(id: 9, name: "Bear"),
    Animal(id: 10, name: "Beaver"),
  ];

  final _items = _animals.map((animal) => MultiSelectItem<Animal>(animal, animal.name)).toList();
  List<Animal?> _selectedAnimals3 = [];
  final _multiSelectKey = GlobalKey<FormFieldState<List<Animal>>>(); // Update here

  @override
  void initState() {
    _selectedAnimals3 = _animals;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: MultiSelectBottomSheetField<Animal?>(
        key: _multiSelectKey,
        initialChildSize: 0.7,
        maxChildSize: 0.95,
        title: const Text("Animals"),
        buttonText: const Text("Favorite Animals"),
        items: _items,
        searchable: true,
        validator: (values) {
          if (values == null || values.isEmpty) {
            return "Required";
          }
          List<String> names = values.map((e) => e!.name).toList(); // Update here
          if (names.contains("Frog")) {
            return "Frogs are weird!";
          }
          return null;
        },
        onConfirm: (List<Animal?> values) {
          // Update here
          setState(() {
            _selectedAnimals3 = values;
          });
          _multiSelectKey.currentState?.validate();
        },
        chipDisplay: MultiSelectChipDisplay(
          onTap: (item) {
            setState(() {
              _selectedAnimals3.remove(item);
            });
            _multiSelectKey.currentState?.validate();
          },
        ),
      ),
    );
  }
}

Я предлагаю вам найти другую библиотеку для достижения ваших требований.

Отредактировано

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

Добавьте изменение pubspecs.yaml со следующей строкой

  multi_select_flutter:
    git: https://github.com/alexsunderlion/multi_select_flutter.git

И ваш код должен быть следующим.

class _ParticipantsToSelectState extends State<ParticipantsToSelect> {
  static final List<Animal> _animals = [
    Animal(id: 1, name: "Lion"),
    Animal(id: 2, name: "Flamingo"),
    Animal(id: 3, name: "Hippo"),
    Animal(id: 4, name: "Horse"),
    Animal(id: 5, name: "Tiger"),
    Animal(id: 6, name: "Penguin"),
    Animal(id: 7, name: "Spider"),
    Animal(id: 8, name: "Snake"),
    Animal(id: 9, name: "Bear"),
    Animal(id: 10, name: "Beaver"),
  ];

  final _items = _animals.map((animal) => MultiSelectItem<Animal>(animal, animal.name)).toList();
  List<Animal> _selectedAnimals3 = [];
  final _multiSelectKey = GlobalKey<FormFieldState<List<Animal>>>(); // Update here

  @override
  void initState() {
    _selectedAnimals3 = _animals;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: MultiSelectBottomSheetField<Animal>(
        key: _multiSelectKey,
        initialChildSize: 0.7,
        maxChildSize: 0.95,
        title: const Text("Animals"),
        buttonText: const Text("Favorite Animals"),
        items: _items,
        searchable: true,
        validator: (values) {
          if (values == null || values.isEmpty) {
            return "Required";
          }
          List<String> names = values.map((e) => e.name).toList(); // Update here
          if (names.contains("Frog")) {
            return "Frogs are weird!";
          }
          return null;
        },
        onConfirm: (List<Animal> values) {
          // Update here
          setState(() {
            _selectedAnimals3 = values;
          });
          _multiSelectKey.currentState?.validate();
        },
        chipDisplay: MultiSelectChipDisplay(
          onTap: (item) {
            setState(() {
              _selectedAnimals3.remove(item);
            });
            _multiSelectKey.currentState?.validate();
          },
        ),
      ),
    );
  }
}

Спасибо, Алекс. Я подтверждаю, что это работает, когда параметр типа MultiSelectBottomSheetField<Animal?> принимает значение NULL. Не могли бы вы предложить другую библиотеку, которая предлагает раскрывающийся список множественного выбора с функцией поиска из коробки?

martin sanzoo 19.02.2023 09:54

Я разветвил библиотеку и изменил ее, чтобы решить проблему null safety. Пожалуйста, просмотрите мои изменения в ответе. Вы можете использовать мою вилку или вилку из моего репо для вашего использования.

Alex Sunder Singh 19.02.2023 17:42

Спасибо Алекс за исправление проблемы в оригинальной библиотеке. Я переключился на ваш и обновил свой код в соответствии с вашим предложением в части «Отредактировано», и все работает так, как ожидалось. Хорошая работа !

martin sanzoo 20.02.2023 08:44

Я надеюсь, что этот ответ может быть принят 😜.

Alex Sunder Singh 20.02.2023 08:47

Другие вопросы по теме