由于类型问题,Flutter 添加到 List<Widget> 崩溃

Posted

技术标签:

【中文标题】由于类型问题,Flutter 添加到 List<Widget> 崩溃【英文标题】:Flutter add to List<Widget> crashes beacuase of type issues 【发布时间】:2021-02-15 06:29:55 【问题描述】:

我有一个不明白的问题。

   Widget build(BuildContext context) 
    List<Widget> menuList = menuCategories.map((category) 
      return ExpansionTile(
          title: CustomExpansionTileHeader(
            icon: category.icon,
            label: category.label,
          ),
          children: category.children
              .map((item) => ListTile(
                    title: Text(item.label),
                    onTap: item.onTap,
                  ))
              .toList());
    ).toList();
    print(menuList);
    menuList.insert(
        0,
        DrawerHeader(
            child: Text(
              '',
              style: TextStyle(color: Colors.white, fontSize: 25),
            ),
            decoration: BoxDecoration(
              color: Colors.green,
              // image: DecorationImage(
              // fit: BoxFit.fill,
              // image: AssetImage('assets/images/cover.jpg'))),
            )));
    return Drawer(
      child: ListView(padding: EdgeInsets.zero, children: menuList

如您所见,我正在尝试使用一些 ExpansionTile 小部件创建列表类型小部件,但还将 DrawerHeader 添加为索引 0。之后,我想在子列表中的抽屉小部件中返回列表。

当我打印 menuList(在将 DrawerHeader 添加到列表之前)时,它打印 [ExpansionTile、ExpansionTile、ExpansionTile、ExpansionTile],当我打印 menuList.runtimeType 时,我得到列表类型 ExpansionTile。 这是我不明白的部分。该列表应该是 Widget 列表,但它以某种方式更改了。

当我将 DrawerHeader 添加到列表时,这会导致崩溃,因为它是不同的提示。

如果这很重要,我正在构建 Flutter 网络应用。

请帮忙:)

【问题讨论】:

我是吗?根据插入方法的颤振文档定义:'在此列表中的位置 [index] 处插入对象。这会将列表的长度增加一,并将索引处或之后的所有对象移向列表的末尾。据我了解,这种方法应该只是增加列表的长度。 【参考方案1】:

当您执行List&lt;Widget&gt; menuList = menuCategories.map((category) 时,请使用通用字段指定类型。 Dart 错误地推断您希望此可迭代对象的类型为 ExpansionTile

List<Widget> menuList = menuCategories.map<Widget>((category) 

更明确地告诉 dart 你希望这是什么类型。

【讨论】:

【参考方案2】:

@Christopher Moore 的答案比下面提到的方法更好。

映射后的tooList()调用总是返回List&lt;ExpansionTile&gt;。这更像是一种 Dart 类型的安全机制。因此,与其插入现有列表,不如将其收集为单独的列表并使用扩展运算符并将这些元素添加到新列表中,如下所示。实时版本在 dartpad 中可用 here。

import 'package:flutter/material.dart';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Drawer Demo'),
        ),
        drawer: MyWidget(),
        body: Center(
          child: Text('Hello'),
        ),
      ),
    );
  


class Item 
  String label;
  Function onTap;
  Item(this.label, this.onTap);


class Category 
  Icon icon;
  String label;
  List<Item> children;
  Category(this.icon, this.label, this.children);


class MyWidget extends StatelessWidget 
  final menuCategories = [
    Category(
      icon: Icon(Icons.ac_unit),
      label: 'ac_unit',
      children: [
        Item(label: 'Voltas'),
        Item(label: 'Haier'),
      ],
    ),
    Category(
      icon: Icon(Icons.computer),
      label: 'computers',
      children: [
        Item(label: 'HP'),
        Item(label: 'Dell'),
      ],
    ),
  ];
  @override
  Widget build(BuildContext context) 
    final categoryList = menuCategories.map((Category category) 
      return ExpansionTile(
          title: ListTile(
            title: Text(category.label),
          ),
          children: category.children
              .map((item) => ListTile(
                    title: Text(item.label),
                    onTap: item.onTap,
                  ))
              .toList());
    ).toList();

    List<Widget> menuList = [
      DrawerHeader(
        child: Text(
          'Categories',
          style: TextStyle(color: Colors.white, fontSize: 25),
        ),
        decoration: BoxDecoration(
          color: Colors.green,
          // image: DecorationImage(
          // fit: BoxFit.fill,
          // image: AssetImage('assets/images/cover.jpg'))),
        ),
      ),
      ...categoryList
    ];
    return Drawer(
        child: ListView(padding: EdgeInsets.zero, children: menuList));
  


您可以在普通 dartpad 中测试以下代码,以验证与您看到的相同的问题。

void main() 
  List<A> menus = [B('s'),B('fd')].toList();
  menus.insert(0, C('1'));
  print(menus);


class A 
  


class B extends A 
  String label;
  B(this.label);


class C extends A 
  String label;
  C(this.label);

【讨论】:

以上是关于由于类型问题,Flutter 添加到 List<Widget> 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 全局List Widget 不刷新问题

Flutter 常见问题四十三限制 TextField 的输入类型

python数据类型的随笔,关于list,dict和set

如何在 Flutter 中将图标添加到 List View Builder 列表中?

将地图列表添加到 Firebase 时出错:Flutter

Flutter 抽象类类型异常