type 'List<dynamic>' is not a subtype of type 'List<Widget>'

FirebaseFlutterDartGoogle Cloud-Firestore

Firebase Problem Overview


I have a snippet of code which I copied from Firestore example:

Widget _buildBody(BuildContext context) {
    return new StreamBuilder(
      stream: _getEventStream(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) return new Text('Loading...');
        return new ListView(
          children: snapshot.data.documents.map((document) {
            return new ListTile(
              title: new Text(document['name']),
              subtitle: new Text("Class"),
            );
          }).toList(),
        );
      },
    );
  }

But I get this error

type 'List<dynamic>' is not a subtype of type 'List<Widget>'

What goes wrong here?

Firebase Solutions


Solution 1 - Firebase

The problem here is that type inference fails in an unexpected way. The solution is to provide a type argument to the map method.

snapshot.data.documents.map<Widget>((document) {
  return new ListTile(
    title: new Text(document['name']),
    subtitle: new Text("Class"),
  );
}).toList()

The more complicated answer is that while the type of children is List<Widget>, that information doesn't flow back towards the map invocation. This might be because map is followed by toList and because there is no way to type annotate the return of a closure.

Solution 2 - Firebase

You can Cast dynamic List to List With specific Type:

List<'YourModel'>.from(_list.where((i) => i.flag == true));

Solution 3 - Firebase

I have solve my problem by converting Map to Widget

      children: snapshot.map<Widget>((data) => 
               _buildListItem(context, data)).toList(),

Solution 4 - Firebase

I had a list of strings in firestore that I was trying to read in my app. I got the same error when I tried to cast it to List of String.

type 'List<dynamic>' is not a subtype of type 'List<Widget>'

This solution helped me. Check it out.

var array = document['array']; // array is now List<dynamic>
List<String> strings = List<String>.from(array);

Solution 5 - Firebase

I think that you use _buildBody in the children properties of some widget, so children expect a List Widget (array of Widget) and _buildBody returns a 'List dynamic'.

In a very simple way, you can use an variable to return it:

// you can build your List of Widget's like you need
List<Widget> widgets = [  Text('Line 1'),  Text('Line 2'),  Text('Line 3'),];

// you can use it like this
Column(
  children: widgets
)

Example (flutter create test1 ; cd test1 ; edit lib/main.dart ; flutter run):

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Widget> widgets = [
    Text('Line 1'),
    Text('Line 2'),
    Text('Line 3'),
  ];

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("List of Widgets Example")),
        body: Column(
          children: widgets
        )
      )
    );
  }

}

Another example using a Widget (oneWidget) within a List of Widgets(arrayOfWidgets). I show how extents a widget (MyButton) to personalize a widget and reduce the size of code:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Widget> arrayOfWidgets = [
    Text('My Buttons'),
    MyButton('Button 1'),
    MyButton('Button 2'),
    MyButton('Button 3'),
  ];

  Widget oneWidget(List<Widget> _lw) { return Column(children: _lw); }

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Widget with a List of Widget's Example")),
        body: oneWidget(arrayOfWidgets)
      )
    );
  }

}

class MyButton extends StatelessWidget {
  final String text;

  MyButton(this.text);

  @override
  Widget build(BuildContext context) {
    return FlatButton(
      color: Colors.red,
      child: Text(text),
      onPressed: (){print("Pressed button '$text'.");},
    );
  }
}

I made a complete example that I use dynamic widgets to show and hide widgets on screen, you can see it running online on dart fiddle, too.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List item = [
    {"title": "Button One", "color": 50},
    {"title": "Button Two", "color": 100},
    {"title": "Button Three", "color": 200},
    {"title": "No show", "color": 0, "hide": '1'},
  ];

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Dynamic Widget - List<Widget>"),backgroundColor: Colors.blue),
        body: Column(
          children: <Widget>[
            Center(child: buttonBar()),
            Text('Click the buttons to hide it'),
          ]
        )
      )
    );
  }

  Widget buttonBar() {
    return Column(
      children: item.where((e) => e['hide'] != '1').map<Widget>((document) {
        return new FlatButton(
          child: new Text(document['title']),
          color: Color.fromARGB(document['color'], 0, 100, 0),
          onPressed: () {
            setState(() {
              print("click on ${document['title']} lets hide it");
              final tile = item.firstWhere((e) => e['title'] == document['title']);
              tile['hide'] = '1';
            });
          },
        );
      }
    ).toList());
  }
}

Maybe it helps someone. If it was is useful to you, let me know clicking in up arrow, please. Thanks.

https://dartpad.dev/b37b08cc25e0ccdba680090e9ef4b3c1

Solution 6 - Firebase

This works for meList<'YourModel'>.from(_list.where((i) => i.flag == true));

Solution 7 - Firebase

changing to the list by adding .toList() resolved the issue

Solution 8 - Firebase

Example:

List<dynamic> listOne = ['111','222']
List<String> ListTwo = listOne.cast<String>();

Solution 9 - Firebase

There was a comment about declaring your list with Instead of "List myList = [1,2,3]"

Declare to "List"<"Widget">" myList [1,2,3]"

Can confirm this solves the error of type 'List' is not a subtype of type 'List'

Solution 10 - Firebase

I think , after changing the type of List from dynamic to String & doing hot reload will give this error , hot restart is the solution..

Remember : hot restart only rebuild the build() function , not the whole class & declaring the List at the top of class is outside of build() function

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionArashView Question on Stackoverflow
Solution 1 - FirebaseJonah WilliamsView Answer on Stackoverflow
Solution 2 - FirebaseC developerView Answer on Stackoverflow
Solution 3 - FirebaseAbdurahman PopalView Answer on Stackoverflow
Solution 4 - FirebaserahulrvpView Answer on Stackoverflow
Solution 5 - Firebaselynx_74View Answer on Stackoverflow
Solution 6 - FirebaseNilotpal KapriView Answer on Stackoverflow
Solution 7 - FirebaseShriraksha bhatView Answer on Stackoverflow
Solution 8 - FirebaseKevinView Answer on Stackoverflow
Solution 9 - Firebasepetras JView Answer on Stackoverflow
Solution 10 - FirebaseMilind GourView Answer on Stackoverflow