loại 'Danh sách <dynamic>' không phải là một loại phụ của loại 'Danh sách <Mục tiêu>'


85

Tôi có một đoạn mã mà tôi đã sao chép từ ví dụ 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(),
        );
      },
    );
  }

Nhưng tôi gặp lỗi này

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

Có gì sai ở đây?

Câu trả lời:


184

Vấn đề ở đây là kiểu suy luận không thành công theo cách không mong muốn. Giải pháp là cung cấp một đối số kiểu cho mapphương thức.

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

Câu trả lời phức tạp hơn là trong khi loại childrenList<Widget>như vậy, thông tin đó không chảy ngược về phía maplời gọi. Điều này có thể là do mapđược theo sau bởi toListvà bởi vì không có cách nào để nhập chú thích trả về của một bao đóng.


1
Có thể liên quan đến mạnh mẽ chế độ hoặc rung sử dụng Dart 2.
Rémi Rousselet

Thay đổi cụ thể này có thể liên quan đến động ở dưới hay còn gọi là "mũi tên mờ" - trước đây có thể chỉ định một Danh sách <dynamic> cho một Danh sách <X>. Điều đó đã che đậy rất nhiều lỗ hổng trong suy luận.
Jonah Williams

1
TBH Tôi đã không quản lý để tái tạo lỗi của anh ta. Vì mã của anh ta được suy ra là một List<ListTile>chẵn mà không chỉ định nó thành map.
Rémi Rousselet

2
Điều đó đã giải quyết được vấn đề. Nhưng hơi lạ, tôi mới làm quen với phi tiêu nên không thể nói là mình đã hiểu nó.
Arash

Tôi đang đối mặt với cùng một vấn đề (Nhưng kịch bản của tôi thì khác). Tôi nghĩ điều này xảy ra là do loại Dart 2 mạnh. Khi tôi thay đổi khai báo biến thành List <Widget>, nó bắt đầu hoạt động.
Manish Kumar

13

Bạn có thể Truyền Danh sách động sang Danh sách Với Loại cụ thể:

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

5

Tôi đã giải quyết vấn đề của mình bằng cách chuyển đổi MapthànhWidget

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

Cảm ơn bạn vì một câu trả lời đơn giản như vậy!
user3079872

3

Tôi nghĩ rằng bạn sử dụng _buildBody trong thuộc tính con của một số widget, vì vậy trẻ em mong đợi một List Widget (mảng Widget) và _buildBody trả về một 'Danh sách động' .

Theo một cách rất đơn giản, bạn có thể sử dụng một biến để trả về nó:

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

Ví dụ ( flaming tạo test1 ; cd test1 ; chỉnh sửa lib / main.dart ; chạy rung ):

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

}

Một ví dụ khác sử dụng một Widget (oneWidget) trong Danh sách các Widget (arrayOfWidgets). Tôi chỉ ra cách mở rộng một tiện ích (MyButton) để cá nhân hóa một tiện ích và giảm kích thước mã:

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

Tôi đã làm một ví dụ hoàn chỉnh rằng tôi sử dụng các widget động để hiển thị và ẩn các widget trên màn hình, bạn cũng có thể thấy nó chạy trực tuyến trên 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());
  }
}

Có thể nó sẽ giúp ai đó. Nếu nó hữu ích cho bạn, vui lòng cho tôi biết bằng cách nhấp vào mũi tên lên. Cảm ơn.

https://dartpad.dev/b37b08cc25e0ccdba680090e9ef4b3c1


Điều này dường như không còn hoạt động. Không thể gán ví dụ Text('My Buttons')vào List<Widget>mảng. BắtThe element type 'Text' can't be assigned to the list type 'Widget' . Cách giải quyết này sẽ là gì?
shaimo

Văn bản là một Tiện ích và có thể là một phần tử của Danh sách <Tiện ích>. Kiểm tra bảng này https://dartpad.dev/6a908fe99f604474fd052731d59d059c và cho tôi biết nó có phù hợp với bạn không.
lynx_74

1

Điều này phù hợp với tôiList<'YourModel'>.from(_list.where((i) => i.flag == true));


0

Để chuyển đổi mỗi mục thành một tiện ích con, hãy sử dụng hàm tạo ListView.builder ().

Nói chung, hãy cung cấp hàm trình tạo để kiểm tra loại mặt hàng bạn đang xử lý và trả về tiện ích con thích hợp cho loại mặt hàng đó.

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),
    );
  },
);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.