measured_card_table 0.1.1 copy "measured_card_table: ^0.1.1" to clipboard
measured_card_table: ^0.1.1 copied to clipboard

A Flutter widget for responsive card-based tables with consistently measured cell widths.

measured_card_table #

Responsive card-table layout widgets for Flutter with consistently measured cell widths.

This package is meant for UI layouts where you want the visual consistency of a table, but the flexibility of cards that adapt cleanly on smaller screens.

  • render each row as your own card, panel, or custom widget
  • keep matching cells aligned across rows by sharing measured widths
  • automatically pack cells into multiple rows when horizontal space is limited

If you have order cards, profile summaries, marketplace listings, or metric-heavy rows, this package helps them stay visually aligned without forcing a traditional table layout.

Demo #

Measured Card Table Demo

Features #

MeasuredCardTable<T> #

Build responsive rows from your own data model.

  • generic row type
  • custom row/card builder
  • automatic multi-row packing based on available width
  • optional MeasuredCardTableController
  • resets measurements when the column id set changes

CardTableColumn<T> #

Describe one logical cell/column.

  • stable id for width measurement
  • fallbackWidth before measurement is available
  • custom cell builder
  • configurable alignment

MeasuredCardTableController #

Share or reset measured column widths.

  • provide a controller manually when needed
  • call reset() when external content changes significantly
  • omit it when the table can manage measurements internally

Installation #

Add to your pubspec.yaml:

dependencies:
  measured_card_table: ^0.1.0

Quick start #

import 'package:flutter/material.dart';
import 'package:measured_card_table/measured_card_table.dart';

class Order {
  final String seller;
  final String price;

  const Order({
    required this.seller,
    required this.price,
  });
}

final orders = [
  Order(seller: 'Aradune Trader', price: '2 Krono'),
  Order(seller: 'Very Long Character Name Trader', price: '999,999 Platinum'),
];

class OrdersView extends StatelessWidget {
  const OrdersView({super.key});

  @override
  Widget build(BuildContext context) {
    return MeasuredCardTable<Order>(
      rows: orders,
      columns: [
        CardTableColumn<Order>(
          id: 'seller',
          fallbackWidth: 180,
          builder: (context, order) => Text(order.seller),
        ),
        CardTableColumn<Order>(
          id: 'price',
          fallbackWidth: 140,
          builder: (context, order) => Text(order.price),
        ),
      ],
      rowBuilder: (context, order, cells) {
        return Card(
          child: Padding(
            padding: const EdgeInsets.all(12),
            child: cells,
          ),
        );
      },
    );
  }
}

Create reusable columns #

import 'package:flutter/material.dart';
import 'package:measured_card_table/measured_card_table.dart';

class Order {
  final String seller;
  final String price;

  const Order({required this.seller, required this.price});
}

List<CardTableColumn<Order>> buildOrderColumns() {
  return [
    CardTableColumn<Order>(
      id: 'seller',
      fallbackWidth: 180,
      builder: (context, order) => Text(order.seller),
    ),
    CardTableColumn<Order>(
      id: 'price',
      fallbackWidth: 140,
      builder: (context, order) => Text(order.price),
    ),
  ];
}

Use a controller #

import 'package:flutter/material.dart';
import 'package:measured_card_table/measured_card_table.dart';

class Order {
  final String seller;

  const Order({required this.seller});
}

class OrdersWithController extends StatefulWidget {
  const OrdersWithController({super.key});

  @override
  State<OrdersWithController> createState() => _OrdersWithControllerState();
}

class _OrdersWithControllerState extends State<OrdersWithController> {
  final controller = MeasuredCardTableController();

  final orders = const [
    Order(seller: 'Aradune Trader'),
    Order(seller: 'Very Long Character Name Trader'),
  ];

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MeasuredCardTable<Order>(
      controller: controller,
      rows: orders,
      columns: [
        CardTableColumn<Order>(
          id: 'seller',
          fallbackWidth: 180,
          builder: (context, order) => Text(order.seller),
        ),
      ],
      rowBuilder: (context, order, cells) => Card(child: cells),
    );
  }

  void resetMeasurements() {
    controller.reset();
  }
}

Concepts #

Rows

Each value in rows is passed to every column builder and to rowBuilder.

Columns

Each CardTableColumn represents one logical cell in every row. Use stable ids, such as seller, price, or status.

Fallback Widths

fallbackWidth is used before measured content widths are available. After layout, the table grows each column width to fit the widest measured content for that column.

Layout Behavior

Cells are NOT placed in a Wrap.

Instead, columns are:

  • measured
  • assigned consistent widths
  • packed into one or more rows based on available width

This avoids overflow and produces stable, predictable layouts.

Controller Lifetime

If you do not pass a controller, the table creates and disposes its own controller. If you do pass one, you own its lifetime.

When to use this package #

  • You want card rows with table-like alignment
  • You want responsive multi-row layouts instead of horizontal scrolling
  • You want custom row/card layouts
  • You have repeated metric-style cells

When NOT to use this package #

  • You need a full data table with sorting/pagination
  • You need virtualization for thousands of visible rows
  • You need strict non-wrapping grid columns

Notes #

Column ids should be stable. If the set or order changes, measurements reset.

For large lists, combine with your own pagination or virtualization.

See the example directory for a full app.

License #

MIT. See LICENSE.

2
likes
160
points
20
downloads

Documentation

API reference

Publisher

verified publisherraidbuilder.app

Weekly Downloads

A Flutter widget for responsive card-based tables with consistently measured cell widths.

Homepage
Repository (GitHub)
View/report issues

Topics

#flutter #table #responsive #layout #cards

License

MIT (license)

Dependencies

flutter

More

Packages that depend on measured_card_table