skip to Main Content

In my Flutter application I need to display a list with one or two item cards per line accordingly to the property singleLine. If it’s true, the item must be displayed in the whole line, if it’s false then I need to check the next item. If both have singleLine as false, then I must display both in the same line, otherwise both will be displayed in separate lines using full width. For example, consider the following list:

final cards = [
  {"title": "Item 1", "singleLine": true},
  {"title": "Item 2", "singleLine": false},
  {"title": "Item 3", "singleLine": false},
  {"title": "Item 4", "singleLine": true},
  {"title": "Item 5", "singleLine": true},
  {"title": "Item 6", "singleLine": false},
  {"title": "Item 7", "singleLine": true},
  {"title": "Item 8", "singleLine": false},
  {"title": "Item 9", "singleLine": false},
];

In this case I want to display this in the screen:

Item 1
Item 2   Item 3
Item 4
Item 5
Item 6
Item 7
Item 8   Item 9

How can I do this?

2

Answers


  1. I think there’s no specific widget that does this, but it can be fulfilled by using some logic.

    Look at the following ListView’s builder:

    class MyHomePage extends StatelessWidget {
      static const List<Map<String, dynamic>> cards = [
        {"title": "Item 1", "singleLine": true},
        {"title": "Item 2", "singleLine": false},
        {"title": "Item 3", "singleLine": false},
        {"title": "Item 4", "singleLine": true},
        {"title": "Item 5", "singleLine": true},
        {"title": "Item 6", "singleLine": false},
        {"title": "Item 7", "singleLine": true},
        {"title": "Item 8", "singleLine": false},
        {"title": "Item 9", "singleLine": false},
      ];
    
      const MyHomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(),
            body: Column(
              children: [
                Text('One or two in a line'),
                Expanded(
                  child: ListView.builder(
                      itemCount: cards.length,
                      itemBuilder: (context, index) {
                        if (index < cards.length - 1) {
                          if (cards[index]['singleLine'])
                            return Text(cards[index]['title']);
                          else {
                            if (!cards[index + 1]['singleLine']) {
                              return Row(
                                children: [
                                  Text(cards[index]['title']),
                                  SizedBox(
                                    width: 25,
                                  ),
                                  Text(cards[index + 1]['title']),
                                ],
                              );
                            } else {
                              return Text(cards[index + 1]['title']);
                            }
                          }
                        }
                      }),
                )
              ],
            ));
      }
    }
    

    and here’s the result:

    enter image description here

    Hope it helps you.

    Login or Signup to reply.
  2. A faster way to implement this would be to just create a 2 dimensional Widget List using a either Text widgets or Row widgets, then setting that as the "children" property of a Column widget as follows:

    class MyHomePage extends StatelessWidget {
      static const List<Map<String, dynamic>> cards = [
        {"title": "Item 1", "singleLine": true},
        {"title": "Item 2", "singleLine": false},
        {"title": "Item 3", "singleLine": false},
        {"title": "Item 4", "singleLine": true},
        {"title": "Item 5", "singleLine": true},
        {"title": "Item 6", "singleLine": false},
        {"title": "Item 7", "singleLine": true},
        {"title": "Item 8", "singleLine": false},
        {"title": "Item 9", "singleLine": false},
      ];
    
      const MyHomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        List<Widget> arrangedCards = [];
        List<Card> cardCache = [];
        for (Map<String, dynamic> card in cards) {
          if (card["singleLine"] == true) {
            if (cardCache.isNotEmpty) {
              arrangedCards.add(Row(
                children: cardCache.toList(),
              ));
              cardCache.clear();
            }
            arrangedCards.add(Card(
              child: Text(card["title"]),
            ));
          } else {
            cardCache.add(Card(
              child: Text(card["title"]),
            ));
          }
        }
        if (cardCache.isNotEmpty) {
          arrangedCards.add(Row(
            children: cardCache,
          ));
        }
    
        return Scaffold(
          appBar: AppBar(),
          body: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: arrangedCards,
          ),
        );
      }
    }
    

    It just traverses the list one time and creates the page using the simplest and fastest built widgets.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search