Flutter - Display multiple items per line in a list

ghz 8months ago ⋅ 89 views

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?

Answers

To achieve the desired layout in your Flutter application, you can use a ListView.builder with a custom implementation for the item layout. Based on the singleLine property of each item, you can conditionally decide how to display the items.

Here's how you can implement it:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('List with Custom Layout')),
        body: ItemList(),
      ),
    );
  }
}

class ItemList extends StatelessWidget {
  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},
  ];

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: cards.length,
      itemBuilder: (context, index) {
        final currentItem = cards[index];
        final previousItem = index > 0 ? cards[index - 1] : null;

        if (currentItem['singleLine'] ||
            (previousItem != null && !previousItem['singleLine'])) {
          // Display the item in full width if it's singleLine or if the previous item is not singleLine
          return ListTile(
            title: Text(currentItem['title']),
          );
        } else {
          // Display two items in the same line
          return Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Expanded(
                child: ListTile(
                  title: Text(previousItem['title']),
                ),
              ),
              Expanded(
                child: ListTile(
                  title: Text(currentItem['title']),
                ),
              ),
            ],
          );
        }
      },
    );
  }
}

In this code:

  • We use a ListView.builder to dynamically create a list of items based on the cards list.
  • Inside the itemBuilder, we check the singleLine property of each item and conditionally decide how to display it.
  • If an item's singleLine property is true, we display it in full width using a ListTile.
  • If an item's singleLine property is false and the previous item's singleLine property is also false, we display both items in the same line using a Row widget with Expanded widgets to ensure equal spacing.
  • Otherwise, if the previous item's singleLine property is true, we display the current item in full width.