Рекурсивный виджет типа Flutter «Список» не является подтипом типа «Список<Карта>» в приведенном типе

#flutter #dart #recursion #types

Вопрос:

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

Здесь процесс обобщен:

  1. извлеките всю древовидную структуру из firestore в виде единого документа. Структура документа выглядит следующим образом (псевдо-документ):
 {  tree: {  total:"3",  name:"A name",  children[  {  total:"4",  name:"Another name",  children:[  {},...  ]  },  {  total:"5",  name:"Main name",  children:[  {},...  ]  },  ]   } }  
  1. используйте виджет для анализа структуры полученного документа, а затем отображения дерева. Поскольку я хотел бы управлять некоторыми состояниями внутри каждого уровня (например, открыть/закрыть, ecc), я бы выбрал виджет с отслеживанием состояния ( Levels ). Вот фрагмент кода (без управления состоянием):
  class MainPage extends StatelessWidget {  const MainPage({Key? key}) : super(key: key);    @override  Widget build(BuildContext context) {  return StreamBuilderlt;DocumentSnapshotlt;Maplt;String, dynamicgt;gt;gt;(  //get doc from firestore!  stream: FirebaseFirestore.instance.collection('taxonomy_tree').doc("main_tree").snapshots(),  builder:(context, AsyncSnapshotlt;DocumentSnapshotlt;Maplt;String, dynamicgt;gt;gt;snapshot){  if(!snapshot.hasData) return Text("Loading");  else {    Maplt;String, dynamicgt;? tree = snapshot.data?.data();  if(tree != null){  return Levels(elements:tree["tree"] as Maplt;String,dynamicgt;,level:0.0);//call Levels Widget  } else return Text("No data");    }  }  );  } }  class Levels extends StatefulWidget {  Levels({Key? key, required this.elements, required this.level}) : super(key: key);   final Maplt;String, dynamicgt; elements;  final double level;    @override  _LevelsState createState() =gt; _LevelsState(); }  class _LevelsState extends Statelt;Levelsgt; {  @override  Widget build(BuildContext context) {    Listlt;Maplt;String, dynamicgt;gt; el = widget.elements.containsKey("children") ? widget.elements["children"] as Listlt;Maplt;String, dynamicgt;gt; :[];    return Padding(  padding: EdgeInsets.only(left:widget.level*10),  child: ListView(  children: [  Text(widget.elements["name"] ?? ""),  Text(widget.elements["total"]?.toString() ?? "0.0"),  //OUCH! el[i] seems to cause an ERROR  for (int i = 0; ilt; el.length;i  ) Levels(elements:el[i], level: widget.level 1)   ]  )  );  } }  

Когда код пытается вызвать Levels с аргументом el[i] , я получаю следующую ошибку:

type 'Listlt;dynamicgt;' is not a subtype of type 'Listlt;Maplt;String, dynamicgt;gt;' in type cast

Я пытался привести el[i] явно ( el[i] as Maplt;String,dynamicgt; ), но все равно получаю ошибку.

Что я упускаю?

Спасибо

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

1. попробуйте создать streambuilder в statefulwidget

2. Hummm…It мне это кажется бессмысленным, но спасибо за комментарий. Я все равно пытался, почему бы и нет, и это не работает

3. Я попросил вас использовать streambuilder для улучшения вашего кода, и это не ответ, так как я его прокомментировал!

Ответ №1:

Это происходит потому, что, когда вы создаете другой объект своего класса Level , ваше состояние

 Listlt;Maplt;String, dynamicgt;gt; el = widget.elements.containsKey("children") ? widget.elements["children"] as Listlt;Maplt;String, dynamicgt;gt; :[];  

снова запускается внутри класса объектов

но ваш следующий children

 children:[  {},...  ]  

у него нет никаких данных, что означает, что он вернется

Картаlt;динамичная, динамичнаяgt;

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

 {  "tree": {  "total": "3",  "name": "A name",  "children": [  {  "total": "4",  "name": "Another name",  "children": [  {"data": 121}  ]  },  {  "total": "5",  "name": "Main name",  "children": [  {"data1": 4545}  ]  },  ]  } }  

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

1. Спасибо @Diwyansh, но это не тот случай. Я опубликовал псевдо-json, настоящий json заполнен правильно. Я думаю, что десериализация-это решение здесь. В любом случае, спасибо

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