Skip to content

Instantly share code, notes, and snippets.

@diegoveloper
Created December 28, 2021 01:53

Revisions

  1. diegoveloper created this gist Dec 28, 2021.
    145 changes: 145 additions & 0 deletions diegoveloper_datatable.dart
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    class DiegoveloperDataTable extends StatefulWidget {
    const DiegoveloperDataTable({Key? key}) : super(key: key);

    @override
    State<DiegoveloperDataTable> createState() => _DiegoveloperDataTableState();
    }

    const itemWidth = 120.0;
    final itemsHeader = List.generate(
    10, (index) => SizedBox(width: itemWidth, child: Text('Header $index')));

    class _DiegoveloperDataTableState extends State<DiegoveloperDataTable> {
    final _controllerHorizontalHeader = CustomScrollController();
    final _controllerHorizontalBody = CustomScrollController();

    void _listenScrollHeader() {
    _controllerHorizontalBody.jumpToWithoutGoingIdleAndKeepingBallistic(
    _controllerHorizontalHeader.offset);
    }

    void _listenScrollBody() {
    _controllerHorizontalHeader.jumpToWithoutGoingIdleAndKeepingBallistic(
    _controllerHorizontalBody.offset);
    }

    @override
    void initState() {
    _controllerHorizontalHeader.addListener(_listenScrollHeader);
    _controllerHorizontalBody.addListener(_listenScrollBody);
    super.initState();
    }

    @override
    void dispose() {
    _controllerHorizontalHeader.removeListener(_listenScrollHeader);
    _controllerHorizontalBody.removeListener(_listenScrollBody);
    _controllerHorizontalHeader.dispose();
    _controllerHorizontalBody.dispose();
    super.dispose();
    }

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    body: CustomScrollView(
    slivers: [
    const SliverToBoxAdapter(
    child: Card(
    child: Center(
    child: FlutterLogo(
    size: 300,
    ),
    ),
    ),
    ),
    SliverAppBar(
    title: SingleChildScrollView(
    controller: _controllerHorizontalHeader,
    scrollDirection: Axis.horizontal,
    child: Row(
    children: itemsHeader,
    ),
    ),
    pinned: true,
    ),
    SliverToBoxAdapter(
    child: SingleChildScrollView(
    controller: _controllerHorizontalBody,
    scrollDirection: Axis.horizontal,
    child: Column(
    children: List.generate(
    20,
    (index) => Row(
    children: List.generate(
    itemsHeader.length,
    (index) => SizedBox(
    width: itemWidth,
    child: ListTile(
    title: Text('Item :$index'),
    ),
    ),
    ),
    ),
    ),
    ),
    ),
    )
    ],
    ),
    );
    }
    }

    class CustomScrollController extends ScrollController {
    CustomScrollController({
    double initialScrollOffset = 0.0,
    bool keepScrollOffset = true,
    String? debugLabel,
    }) : super(
    initialScrollOffset: initialScrollOffset,
    keepScrollOffset: keepScrollOffset,
    debugLabel: debugLabel);

    @override
    _SilentScrollPosition createScrollPosition(
    ScrollPhysics physics,
    ScrollContext context,
    ScrollPosition? oldPosition,
    ) {
    return _SilentScrollPosition(
    physics: physics,
    context: context,
    oldPosition: oldPosition,
    initialPixels: initialScrollOffset,
    );
    }

    void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
    assert(positions.isNotEmpty, 'ScrollController not attached.');
    for (_SilentScrollPosition position in List<ScrollPosition>.from(positions)
    .whereType<_SilentScrollPosition>()) {
    position.jumpToWithoutGoingIdleAndKeepingBallistic(value);
    }
    }
    }

    class _SilentScrollPosition extends ScrollPositionWithSingleContext {
    _SilentScrollPosition({
    required ScrollPhysics physics,
    required ScrollContext context,
    ScrollPosition? oldPosition,
    double? initialPixels,
    }) : super(
    physics: physics,
    context: context,
    oldPosition: oldPosition,
    initialPixels: initialPixels,
    );

    void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
    if (pixels != value) {
    forcePixels(value);
    }
    }
    }