material_table_view 3.0.0 copy "material_table_view: ^3.0.0" to clipboard
material_table_view: ^3.0.0 copied to clipboard

outdated

Flutter library providing a both horizontally and vertically scrollable material-style table widget.

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:material_table_view/default_animated_switcher_transition_builder.dart';
import 'package:material_table_view/material_table_view.dart';
import 'package:material_table_view/shimmer_placeholder_shade.dart';

void main() => runApp(const MyApp());

const _title = 'material_table_view demo';

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

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: _title,
        theme: _appTheme(Brightness.light),
        darkTheme: _appTheme(Brightness.dark),
        home: const MyHomePage(),
      );

  ThemeData _appTheme(Brightness brightness) => ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blueGrey,
          brightness: brightness,
        ),
        dividerColor: const Color(0x60808080),
        dividerTheme: const DividerThemeData(
          color: Color(0x60808080),
        ),
      );
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

const _columnsPowerOfTwo = 12;
const _rowCount = (1 << 31) - 1;

class _MyHomePageState extends State<MyHomePage> {
  final selection = <int>{};
  int placeholderOffsetIndex = 0;

  late Timer periodicPlaceholderOffsetIncreaseTimer;

  @override
  void initState() {
    super.initState();
    periodicPlaceholderOffsetIncreaseTimer = Timer.periodic(
        const Duration(milliseconds: 1000),
        (timer) => setState(() => placeholderOffsetIndex++));
  }

  @override
  void dispose() {
    periodicPlaceholderOffsetIncreaseTimer.cancel();

    super.dispose();
  }

  /// This is used to wrap both regular and placeholder rows to achieve fade
  /// transition between them.
  Widget _wrapRow(Widget child) => AnimatedSwitcher(
        duration: const Duration(milliseconds: 200),
        transitionBuilder: tableRowDefaultAnimatedSwitcherTransitionBuilder,
        child: child,
      );

  @override
  Widget build(BuildContext context) {
    final textStyle = Theme.of(context).textTheme.bodyMedium;
    final selectedTextStyle = textStyle?.copyWith(
        color: Theme.of(context).colorScheme.onPrimaryContainer);

    const shimmerBaseColor = Color(0x20808080);
    const shimmerHighlightColor = Color(0x40FFFFFF);

    return Scaffold(
      appBar: AppBar(title: const Text(_title)),
      body: LayoutBuilder(
        builder: (context, constraints) => ShimmerPlaceholderShadeProvider(
          loopDuration: const Duration(seconds: 2),
          colors: const [
            shimmerBaseColor,
            shimmerHighlightColor,
            shimmerBaseColor,
            shimmerHighlightColor,
            shimmerBaseColor
          ],
          stops: const [.0, .45, .5, .95, 1],
          builder: (context, placeholderShade) => TableView.builder(
            columns: [
              const TableColumn(
                width: 56.0,
                freezePriority: 1 * (_columnsPowerOfTwo + 1),
              ),
              for (var i = 1; i <= 1 << _columnsPowerOfTwo; i++)
                TableColumn(
                  width: 64,
                  freezePriority: 1 *
                      (_columnsPowerOfTwo -
                          (_getPowerOfTwo(i) ?? _columnsPowerOfTwo)),
                ),
            ],
            rowHeight: 48.0 + 4 * Theme.of(context).visualDensity.vertical,
            rowCount: _rowCount - 1,
            rowBuilder: (context, row, contentBuilder) {
              final selected = selection.contains(row);
              return (row + placeholderOffsetIndex) % 99 < 33
                  ? null
                  : _wrapRow(
                      AnimatedContainer(
                        duration: const Duration(milliseconds: 200),
                        color: Theme.of(context)
                            .colorScheme
                            .primaryContainer
                            .withAlpha(selected ? 0xFF : 0),
                        child: Material(
                          type: MaterialType.transparency,
                          child: InkWell(
                            onTap: () => setState(() {
                              selection.clear();
                              selection.add(row);
                            }),
                            child: contentBuilder(
                              context,
                              (context, column) => column == 0
                                  ? Checkbox(
                                      value: selection.contains(row),
                                      onChanged: (value) => setState(() =>
                                          (value ?? false)
                                              ? selection.add(row)
                                              : selection.remove(row)))
                                  : Align(
                                      alignment: Alignment.centerLeft,
                                      child: Padding(
                                        padding:
                                            const EdgeInsets.only(left: 8.0),
                                        child: Text(
                                          '${(row + 2) * column}',
                                          style: selected
                                              ? selectedTextStyle
                                              : textStyle,
                                          overflow: TextOverflow.fade,
                                          maxLines: 1,
                                          softWrap: false,
                                        ),
                                      ),
                                    ),
                            ),
                          ),
                        ),
                      ),
                    );
            },
            placeholderBuilder: (context, contentBuilder) => _wrapRow(
              contentBuilder(
                context,
                (context, column) => column == 0
                    ? const Checkbox(
                        value: false,
                        onChanged: _dummyCheckboxOnChanged,
                      )
                    : const Padding(
                        padding: EdgeInsets.all(8.0),
                        child: DecoratedBox(
                            decoration: BoxDecoration(
                                color: Colors.white,
                                borderRadius:
                                    BorderRadius.all(Radius.circular(16)))),
                      ),
              ),
            ),
            placeholderShade: placeholderShade,
            headerBuilder: (context, contentBuilder) => contentBuilder(
              context,
              (context, column) => column == 0
                  ? Checkbox(
                      value: selection.isEmpty ? false : null,
                      tristate: true,
                      onChanged: (value) {
                        if (!(value ?? true)) {
                          setState(() => selection.clear());
                        }
                      },
                    )
                  : Padding(
                      padding: const EdgeInsets.only(left: 8.0),
                      child: Align(
                        alignment: Alignment.centerLeft,
                        child: Text("$column"),
                      ),
                    ),
            ),
            footerBuilder: (context, contentBuilder) => contentBuilder(
              context,
              (context, column) => Padding(
                padding: const EdgeInsets.only(left: 8.0),
                child: Align(
                  alignment:
                      column == 0 ? Alignment.center : Alignment.centerLeft,
                  child: Text(column == 0 ? '${selection.length}' : '$column'),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  /// This is used to create const [Checkbox]es that are enabled.
  static void _dummyCheckboxOnChanged(bool? _) {}

  static int? _getPowerOfTwo(int number) {
    assert(!number.isNegative);
    if (number == 0) return null;

    for (int i = 0;; i++) {
      if (number & 1 == 1) {
        return ((number & ~1) >> 1) == 0 ? i : null;
      }

      number = (number & ~1) >> 1;
    }
  }
}
169
likes
0
points
2.9k
downloads

Publisher

verified publishernikolaynik.com

Weekly Downloads

Flutter library providing a both horizontally and vertically scrollable material-style table widget.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on material_table_view