类型'List <dynamic>'不是类型'List <Widget>'的子类型


85

我有一段代码是从Firestore示例中复制的:

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(),
        );
      },
    );
  }

但是我得到这个错误

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

这里出什么问题了?

Answers:


184

这里的问题是类型推断以意外的方式失败。解决方案是为该map方法提供类型实参。

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

更为复杂的答案是,尽管类型childrenList<Widget>,但信息不会流向map调用。这可能是因为map紧随其后的toList原因,并且是因为无法键入注释来返回闭包。


1
可能与使用Dart 2的强模式或颤动有关。
RémiRousselet '18

此特定更改可能与动态相关,也称为底部“模糊箭头”-以前可以将List <dynamic>分配给List <X>。那掩盖了很多推理上的空白。
乔纳·威廉姆斯

1
TBH我没有设法重现他的错误。由于他的代码在List<ListTile>没有指定的情况下被推断为偶数map
雷米Rousselet

2
好了,解决了这个问题。但这有点奇怪,我是飞镖的新手,所以我真的不能说我理解它。
Arash

我面临着同样的问题(但我的情况有所不同)。我认为这是由于Dart 2强类型而发生的。一旦将变量声明更改为List <Widget>,它便开始工作。
Manish Kumar,

13

您可以将动态列表转换为具有特定类型的列表:

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


3

我认为您在某些小部件的children属性中使用了_buildBody ,因此孩子希望使用List WidgetWidget的数组),并且_buildBody返回一个'List dynamic'

您可以通过一种非常简单的方式使用变量将其返回:

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

示例(flutter create test1cd test1编辑lib / main.dartflutter 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
        )
      )
    );
  }

}

小部件列表(arrayOfWidgets)中使用小部件(oneWidget)的另一个示例。我展示了小部件(MyButton)如何扩展个性化小部件并减少代码大小:

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'.");},
    );
  }
}

了一个完整的示例,我使用动态窗口小部件在屏幕上显示和隐藏窗口小部件,您也可以在dart fiddle上看到它在线运行。

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

也许对某人有帮助。如果对您有用,请告诉我单击向上箭头。谢谢。

https://dartpad.dev/b37b08cc25e0ccdba680090e9ef4b3c1


这似乎不再起作用。无法分配如Text('My Buttons')List<Widget>阵。得到The element type 'Text' can't be assigned to the list type 'Widget'。有什么解决方法?
shaimo

文本是一个小部件,可以是List <Widget>的元素。检查此垫https://dartpad.dev/6a908fe99f604474fd052731d59d059c并告诉我它是否对您有用。
lynx_74


0

要将每个项目转换为小部件,请使用ListView.builder()构造函数。

通常,提供一个构建器功能,该功能可检查您要处理的项目类型,并为该类型的项目返回适当的小部件。

ListView.builder(
  // Let the ListView know how many items it needs to build.
  itemCount: items.length,
  // Provide a builder function. This is where the magic happens.
  // Convert each item into a widget based on the type of item it is.
  itemBuilder: (context, index) {
    final item = items[index];

    return ListTile(
      title: item.buildTitle(context),
      subtitle: item.buildSubtitle(context),
    );
  },
);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.