dynamic_table_scroll 0.0.2
dynamic_table_scroll: ^0.0.2 copied to clipboard
A high-performance 2D Flutter table with sticky headers & pinned columns, 2D bidirectional scrolling, horizontal virtualization, and auto-fit column widths.
dynamic_table_scroll #
A performant, customizable 2D Flutter table package featuring sticky column titles (headers) when scrolling vertically and sticky columns (frozen columns) when scrolling horizontally.
Features #
- 📌 Sticky Header (Vertical Scroll): Column titles remain pinned at the top while scrolling down through rows (enabled by default, customizable via
isHeaderPinned). - 📌 Sticky Columns (Horizontal Scroll): One or more left columns remain pinned while scrolling horizontally through wide tables (enabled by default via
isPinnedorpinnedColumnCount). - 📌 Corner Cell Anchoring: Top-left corner headers remain completely stationary on both axes.
- ⚡ Horizontal Column Virtualization (Windowing): Only visible columns in viewport (+ overscan buffer) are rendered, supporting 100+ to 200+ columns at 60/120 FPS.
- 📏 Auto-Fit Column Widths with Min/Max Constraints: Automatically measures header and sample rows with
autoFit: true, constrained byminWidthandmaxWidth. - ⚡ Linked 2D Scroll Synchronization: Fluid multi-directional scrolling with mouse wheel, trackpad, touch drag, and scrollbars.
- 🎨 Full Style Customization & Compact Density: Configure header & row heights, compact fonts, zebra striping, sticky elevation shadows, custom borders, and paddings.
- 🎮 Programmatic Control: Use
DynamicTableControllerto jump or animate to specific rows, offsets, or columns. - 💡 Interactive Callbacks: Support for
onRowTap,onRowLongPress, and customrowBuilder.
Getting Started #
Add dynamic_table_scroll to your pubspec.yaml:
dependencies:
dynamic_table_scroll:
path: ../dynamic_table_scroll # or from git/pub.dev
Import the package:
import 'package:dynamic_table_scroll/dynamic_table_scroll.dart';
Basic Usage #
import 'package:flutter/material.dart';
import 'package:dynamic_table_scroll/dynamic_table_scroll.dart';
class MyTableScreen extends StatelessWidget {
const MyTableScreen({super.key});
@override
Widget build(BuildContext context) {
final columns = [
DynamicTableColumn<Map<String, dynamic>>(
id: 'id',
title: const Text('ID'),
width: 70,
isPinned: true, // Freeze on horizontal scroll
cellBuilder: (context, data, index) => Text('${data['id']}'),
),
DynamicTableColumn<Map<String, dynamic>>(
id: 'name',
title: const Text('Full Name'),
width: 160,
isPinned: true, // Freeze on horizontal scroll
cellBuilder: (context, data, index) => Text(data['name']),
),
DynamicTableColumn<Map<String, dynamic>>(
id: 'email',
title: const Text('Email'),
width: 200,
cellBuilder: (context, data, index) => Text(data['email']),
),
DynamicTableColumn<Map<String, dynamic>>(
id: 'role',
title: const Text('Role'),
width: 120,
cellBuilder: (context, data, index) => Text(data['role']),
),
];
final rows = List.generate(
100,
(i) => {
'id': i + 1,
'name': 'User ${i + 1}',
'email': 'user${i + 1}@example.com',
'role': i % 2 == 0 ? 'Admin' : 'Member',
},
);
return Scaffold(
appBar: AppBar(title: const Text('Dynamic Table')),
body: DynamicTableScrollView<Map<String, dynamic>>(
columns: columns,
rows: rows,
isHeaderPinned: true, // Sticky header (default: true)
pinnedColumnCount: 2, // Pinned columns count (default: auto from columns)
onRowTap: (item, index) {
print('Tapped row: $index -> $item');
},
),
);
}
}
Custom Styling #
DynamicTableScrollView<MyData>(
columns: columns,
rows: rows,
style: DynamicTableStyle(
headerHeight: 52.0,
rowHeight: 48.0,
headerBackgroundColor: const Color(0xFFF1F5F9),
bodyBackgroundColor: Colors.white,
alternateRowColor: const Color(0xFFF8FAFC),
pinnedColumnBackgroundColor: const Color(0xFFF8FAFC),
headerTextStyle: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
cellTextStyle: const TextStyle(fontSize: 14, color: Color(0xFF334155)),
cellBorderSide: const BorderSide(color: Color(0xFFE2E8F0)),
stickyHeaderShadow: const [
BoxShadow(color: Color(0x1A000000), offset: Offset(0, 3), blurRadius: 6),
],
stickyColumnShadow: const [
BoxShadow(color: Color(0x1A000000), offset: Offset(3, 0), blurRadius: 6),
],
),
)
Controller #
final controller = DynamicTableController();
// Pass to widget
DynamicTableScrollView(
controller: controller,
columns: columns,
rows: rows,
);
// Jump or animate
controller.jumpToRow(25);
controller.animateToRow(50, duration: Duration(milliseconds: 500), curve: Curves.easeOut);
controller.jumpToHorizontal(200);