Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add List<Widget> to ListView.children dynamically

I am trying to dynamically build part of my ListView.children[], yet I fail to push them to already existing array. Here is my simplified code:

  Widget buildNavigationDrawer(BuildContext context) {
    return Drawer(
      child: ListView(
        // Important: Remove any padding from the ListView.
        padding: EdgeInsets.zero,
        children: <Widget>[
          DrawerHeader(...code for header of drawer),

          _buildUserGroups(context).map((Widget item)=> item),

          ListTile(
            leading: Icon(Icons.account_circle),
            title: Text('Settings'),
            onTap: () {
              Navigator.push(
                  context,
                  FadeTransitionRoute(
                      builder: (context) => MainSettingsPage()));
            },
          ),
        ],
      ),
    );
  }

Where _buildUserGroups() function looks like this (simplified):

  List<Widget> _buildUserGroups(BuildContext context) {
    var userGroup = List<Widget>();
    userGroup.add(Text("Users"));

    for (var i = 0; i < 5; i++) {
      userGroup.add(Text("User " + i.toString()));
    }

    return userGroup;
  }

I have tried to use _buildUserGroups(context).forEach(), _buildUserGroups(context).map(), or simply dumping the result like _buildUserGroups(context); yet it fails and says the same error message:

[dart] The element type 'Iterable' can't be assigned to the list type 'Widget'.

I am quite sure the is a way how to do it, but I cannot figure it out. Any help or suggestion in respect to this matter would be highly appreciated as I am quite stuck at the moment.

like image 907
Robert J. Avatar asked Oct 14 '18 09:10

Robert J.


People also ask

How do you add a list item dynamically in flutter?

Let us add a TextField to add a list item to the list dynamically. Run this application, and you should see a TextField widget and a Add button to add an item to the list dynamically. Type in some name and click on Add button. The item will be added at the top of the list dynamically.

How do I add widgets dynamically in flutter?

First, we will create a stateful widget which will look something like this. Now, add Scaffold in our widget method of the stateful widget which will be returning the empty container and floating action button which is going to add the text fields on the press of this button.

How do I add a widget to a list?

To configure a list widget, tap on the widget while the home screen is still in jiggle mode. Or when not in jiggle mode, touch-and-hold on the widget and select Edit Widget from the pop-up menu. For single-list widgets, tap the List field and select the desired list to display in the widget.


1 Answers

As pointed out by other answers, the _buildUserGroups(context) is the problem, as it returns a list of widgets, resulting in a nested list.

Since Dart 2.3 (introduced to Flutter at Google I/O '19), you can use the spread operator ..., which will unwrap the inner list, so its elements become elements of the outer list:

Widget buildNavigationDrawer(BuildContext context) {
  return Drawer(
    child: ListView(
      children: [
        DrawerHeader(...),
        ..._buildUserGroups(context),
        ListTile(...)
      ],
    ),
  );
}

For more information about what the spread operator does, check out Dart's language tour.


Original answer (before Dart 2.3):

You can wrap the function call in a Column or ExpansionTile.

However, this introduces a new widget into the widget tree. Admittedly, the impact on performance is minimal, but in my opinion, a cleaner solution would be to construct the list of widgets like this:

Widget buildNavigationDrawer(BuildContext context) {
  final items = <Widget>[]
    ..add(DrawerHeader(...))
    ..addAll(_buildUserGroups(context))
    ..add(ListTile(...));

  return Drawer(child: ListView(children: items));
}

If you insist on an inline solution, you can also use .followedBy(...) to add items to the list:

Widget buildNavigationDrawer(BuildContext context) {
  return Drawer(
    child: ListView(
      children: [ DrawerHeader(...) ]
        .followedBy(_buildUserGroups(context))
        .followedBy([ ListTile(...) ])
    ),
  );
}
like image 178
Marcel Avatar answered Oct 09 '22 09:10

Marcel