Arash
Arash

Reputation: 12425

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

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?

Upvotes: 213

Views: 227612

Answers (11)

fazal ur Rehman
fazal ur Rehman

Reputation: 404

Changing

List list = [];

to this:

List<Widget> list = [];

Solved My Problem!!

Upvotes: 1

nico
nico

Reputation: 81

My Solution is, you can cast List<dynamic> into List<Widget>, you can add a simple code after snapshot.data.documents.map into snapshot.data.documents.map<Widget>, like the code i will show you below

From this

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

Into this

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

Upvotes: 8

Abdurahman Popal
Abdurahman Popal

Reputation: 3009

I have solve my problem by converting Map to Widget

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

Upvotes: 33

Sriraksha
Sriraksha

Reputation: 569

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

Upvotes: 1

Milind Gour
Milind Gour

Reputation: 131

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

Upvotes: 3

rahulrvp
rahulrvp

Reputation: 2126

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);

Upvotes: 67

Kevin
Kevin

Reputation: 381

Example:

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

Upvotes: 4

nilotpal
nilotpal

Reputation: 87

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

Upvotes: 4

lynx_74
lynx_74

Reputation: 1761

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

Upvotes: 7

C developer
C developer

Reputation: 371

You can Cast dynamic List to List With specific Type:

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

Upvotes: 37

Jonah Williams
Jonah Williams

Reputation: 21441

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.

Upvotes: 429

Related Questions