Add a horizontal scrollbar to DevTools tables (#9482)

diff --git a/packages/devtools_app/lib/src/screens/memory/panes/profile/profile_view.dart b/packages/devtools_app/lib/src/screens/memory/panes/profile/profile_view.dart
index 16c3827..7325b42 100644
--- a/packages/devtools_app/lib/src/screens/memory/panes/profile/profile_view.dart
+++ b/packages/devtools_app/lib/src/screens/memory/panes/profile/profile_view.dart
@@ -404,6 +404,7 @@
             columns: _columns,
             defaultSortColumn: _columns.first,
             defaultSortDirection: SortDirection.ascending,
+            sizeColumnsToFit: false,
           ),
         );
       },
@@ -426,6 +427,8 @@
 
 class AllocationProfileTableViewState
     extends State<AllocationProfileTableView> {
+  static const _scrollbarHeight = 10.0;
+
   @override
   void initState() {
     super.initState();
@@ -459,7 +462,10 @@
                   // and columns) and one data row. We add a slight padding to
                   // ensure the underlying scrollable area has enough space to not
                   // display a scroll bar.
-                  height: defaultRowHeight + defaultHeaderHeight * 2 + 1,
+                  height:
+                      defaultRowHeight +
+                      defaultHeaderHeight * 2 +
+                      _scrollbarHeight,
                   child: _GCStatsTable(controller: widget.controller),
                 ),
                 const ThickDivider(),
diff --git a/packages/devtools_app/lib/src/shared/table/_flat_table.dart b/packages/devtools_app/lib/src/shared/table/_flat_table.dart
index c6fa4a8..087148c 100644
--- a/packages/devtools_app/lib/src/shared/table/_flat_table.dart
+++ b/packages/devtools_app/lib/src/shared/table/_flat_table.dart
@@ -317,7 +317,6 @@
 
   Widget _buildRow({
     required BuildContext context,
-    required LinkedScrollControllerGroup linkedScrollControllerGroup,
     required int index,
     required List<double> columnWidths,
     required bool isPinned,
@@ -327,7 +326,6 @@
     final data = isPinned ? pinnedData : tableController.tableData.value.data;
     if (index >= data.length) {
       return TableRow<T>.filler(
-        linkedScrollControllerGroup: linkedScrollControllerGroup,
         columns: tableController.columns,
         columnGroups: tableController.columnGroups,
         columnWidths: columnWidths,
@@ -344,7 +342,6 @@
       builder: (context, selected, _) {
         return TableRow<T>(
           key: widget.keyFactory(node),
-          linkedScrollControllerGroup: linkedScrollControllerGroup,
           node: node,
           onPressed: (T? selection) {
             widget.selectionNotifier.value = selection;
diff --git a/packages/devtools_app/lib/src/shared/table/_table_column.dart b/packages/devtools_app/lib/src/shared/table/_table_column.dart
index 521d212..79d7c2a 100644
--- a/packages/devtools_app/lib/src/shared/table/_table_column.dart
+++ b/packages/devtools_app/lib/src/shared/table/_table_column.dart
@@ -129,15 +129,12 @@
   const _ColumnGroupHeaderRow({
     required this.groups,
     required this.columnWidths,
-    required this.scrollController,
   });
 
   final List<ColumnGroup> groups;
 
   final List<double> columnWidths;
 
-  final ScrollController scrollController;
-
   @override
   Widget build(BuildContext context) {
     return Container(
@@ -147,7 +144,6 @@
       ),
       child: ListView.builder(
         scrollDirection: Axis.horizontal,
-        controller: scrollController,
         itemCount: groups.length + groups.numSpacers,
         itemBuilder: (context, int i) {
           if (i % 2 == 1) {
diff --git a/packages/devtools_app/lib/src/shared/table/_table_row.dart b/packages/devtools_app/lib/src/shared/table/_table_row.dart
index 7634388..9161ca1 100644
--- a/packages/devtools_app/lib/src/shared/table/_table_row.dart
+++ b/packages/devtools_app/lib/src/shared/table/_table_row.dart
@@ -18,7 +18,6 @@
   /// [node].
   const TableRow({
     super.key,
-    required this.linkedScrollControllerGroup,
     required this.node,
     required this.columns,
     required this.columnWidths,
@@ -44,7 +43,6 @@
   /// Constructs a [TableRow] that is empty.
   const TableRow.filler({
     super.key,
-    required this.linkedScrollControllerGroup,
     required this.columns,
     required this.columnWidths,
     this.columnGroups,
@@ -71,7 +69,6 @@
   /// of any [node].
   const TableRow.tableColumnHeader({
     super.key,
-    required this.linkedScrollControllerGroup,
     required this.columns,
     required this.columnWidths,
     required this.columnGroups,
@@ -98,7 +95,6 @@
   /// [node].
   const TableRow.tableColumnGroupHeader({
     super.key,
-    required this.linkedScrollControllerGroup,
     required this.columnGroups,
     required this.columnWidths,
     required this.sortColumn,
@@ -121,8 +117,6 @@
        enableHoverHandling = false,
        _rowType = _TableRowType.columnGroupHeader;
 
-  final LinkedScrollControllerGroup linkedScrollControllerGroup;
-
   final T? node;
 
   final List<ColumnData<T>> columns;
@@ -200,8 +194,6 @@
         SearchableMixin {
   Key? contentKey;
 
-  late ScrollController scrollController;
-
   bool isSearchMatch = false;
 
   bool isActiveSearchMatch = false;
@@ -216,7 +208,6 @@
   void initState() {
     super.initState();
     contentKey = ValueKey(this);
-    scrollController = widget.linkedScrollControllerGroup.addAndGet();
     _initSearchListeners();
 
     _rowDisplayParts = _rowDisplayPartsHelper();
@@ -242,11 +233,6 @@
   void didUpdateWidget(TableRow<T> oldWidget) {
     super.didUpdateWidget(oldWidget);
     setExpanded(widget.isExpanded);
-    if (oldWidget.linkedScrollControllerGroup !=
-        widget.linkedScrollControllerGroup) {
-      scrollController.dispose();
-      scrollController = widget.linkedScrollControllerGroup.addAndGet();
-    }
 
     _rowDisplayParts = _rowDisplayPartsHelper();
 
@@ -257,12 +243,6 @@
   }
 
   @override
-  void dispose() {
-    scrollController.dispose();
-    super.dispose();
-  }
-
-  @override
   Widget build(BuildContext context) {
     final node = widget.node;
     final widgetOnPressed = widget.onPressed;
@@ -530,18 +510,13 @@
       return _ColumnGroupHeaderRow(
         groups: groups,
         columnWidths: widget.columnWidths,
-        scrollController: scrollController,
       );
     }
 
     Widget rowContent = Padding(
       padding: const EdgeInsets.symmetric(horizontal: defaultSpacing),
-      child: ExtentDelegateListView(
-        scrollDirection: Axis.horizontal,
-        physics: const ClampingScrollPhysics(),
-        controller: scrollController,
-        extentDelegate: rowExtentDelegate,
-        childrenDelegate: SliverChildBuilderDelegate((context, int i) {
+      child: Row(
+        children: List.generate(_rowDisplayParts.length, (int i) {
           final columnIndexMap = _columnIndexMapHelper(_rowDisplayParts);
           final displayTypeForIndex = _rowDisplayParts[i];
           switch (displayTypeForIndex) {
@@ -559,7 +534,7 @@
             case _TableRowPartDisplayType.columnGroupSpacer:
               return const _ColumnGroupSpacer();
           }
-        }, childCount: _rowDisplayParts.length),
+        }),
       ),
     );
 
diff --git a/packages/devtools_app/lib/src/shared/table/_tree_table.dart b/packages/devtools_app/lib/src/shared/table/_tree_table.dart
index 4bc64ef..1880f50 100644
--- a/packages/devtools_app/lib/src/shared/table/_tree_table.dart
+++ b/packages/devtools_app/lib/src/shared/table/_tree_table.dart
@@ -282,7 +282,6 @@
 
   Widget _buildRow({
     required BuildContext context,
-    required LinkedScrollControllerGroup linkedScrollControllerGroup,
     required int index,
     required List<double> columnWidths,
     required bool isPinned,
@@ -293,7 +292,6 @@
       node.index = index;
       return TableRow<T>(
         key: widget.keyFactory(node),
-        linkedScrollControllerGroup: linkedScrollControllerGroup,
         node: node,
         onPressed: (item) => _onItemPressed(item, index),
         backgroundColor: alternatingColorForIndex(
diff --git a/packages/devtools_app/lib/src/shared/table/table.dart b/packages/devtools_app/lib/src/shared/table/table.dart
index 35b7853..a7a1ce4 100644
--- a/packages/devtools_app/lib/src/shared/table/table.dart
+++ b/packages/devtools_app/lib/src/shared/table/table.dart
@@ -13,7 +13,6 @@
 
 import '../primitives/collapsible_mixin.dart';
 import '../primitives/extent_delegate_list.dart';
-import '../primitives/flutter_widgets/linked_scroll_controller.dart';
 import '../primitives/trees.dart';
 import '../primitives/utils.dart';
 import '../ui/common_widgets.dart';
@@ -32,7 +31,6 @@
 typedef IndexedScrollableWidgetBuilder =
     Widget Function({
       required BuildContext context,
-      required LinkedScrollControllerGroup linkedScrollControllerGroup,
       required int index,
       required List<double> columnWidths,
       required bool isPinned,
@@ -113,9 +111,9 @@
 @visibleForTesting
 class DevToolsTableState<T> extends State<DevToolsTable<T>>
     with AutoDisposeMixin {
-  late LinkedScrollControllerGroup _linkedHorizontalScrollControllerGroup;
   late ScrollController scrollController;
   late ScrollController pinnedScrollController;
+  late ScrollController _horizontalScrollbarController;
 
   late List<T> _data;
 
@@ -134,13 +132,13 @@
 
     _initDataAndAddListeners();
 
-    _linkedHorizontalScrollControllerGroup = LinkedScrollControllerGroup();
-
     final initialScrollOffset = widget.preserveVerticalScrollPosition
         ? widget.tableController.tableUiState.scrollOffset
         : 0.0;
     widget.tableController.initScrollController(initialScrollOffset);
     scrollController = widget.tableController.verticalScrollController!;
+    _horizontalScrollbarController =
+        widget.tableController.horizontalScrollController!;
 
     if (widget.startScrolledAtBottom) {
       WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -373,7 +371,6 @@
   Widget _buildItem(BuildContext context, int index, {bool isPinned = false}) {
     return widget.rowBuilder(
       context: context,
-      linkedScrollControllerGroup: _linkedHorizontalScrollControllerGroup,
       index: index,
       columnWidths: adjustedColumnWidths,
       isPinned: isPinned,
@@ -406,95 +403,99 @@
       scrollController.jumpTo(tableUiState.scrollOffset);
     }
 
-    // TODO(kenz): add horizontal scrollbar.
     return LayoutBuilder(
       builder: (context, constraints) {
         final viewWidth = constraints.maxWidth;
         _adjustColumnWidthsForViewSize(viewWidth);
-        return SelectionArea(
-          child: SizedBox(
-            width: max(viewWidth, _tableWidthForOriginalColumns),
-            child: Column(
-              crossAxisAlignment: CrossAxisAlignment.stretch,
-              children: [
-                if (showColumnGroupHeader)
-                  TableRow<T>.tableColumnGroupHeader(
-                    linkedScrollControllerGroup:
-                        _linkedHorizontalScrollControllerGroup,
-                    columnGroups: columnGroups,
-                    columnWidths: adjustedColumnWidths,
-                    sortColumn: sortColumn,
-                    sortDirection: tableUiState.sortDirection,
-                    secondarySortColumn:
-                        widget.tableController.secondarySortColumn,
-                    onSortChanged: widget.tableController.sortDataAndNotify,
-                    tall: widget.tallHeaders,
-                    backgroundColor: widget.headerColor,
-                  ),
-                // TODO(kenz): add support for excluding column headers.
-                TableRow<T>.tableColumnHeader(
-                  key: const Key('Table header'),
-                  linkedScrollControllerGroup:
-                      _linkedHorizontalScrollControllerGroup,
-                  columns: widget.tableController.columns,
-                  columnGroups: columnGroups,
-                  columnWidths: adjustedColumnWidths,
-                  sortColumn: sortColumn,
-                  sortDirection: tableUiState.sortDirection,
-                  secondarySortColumn:
-                      widget.tableController.secondarySortColumn,
-                  onSortChanged: widget.tableController.sortDataAndNotify,
-                  tall: widget.tallHeaders,
-                  backgroundColor: widget.headerColor,
-                ),
-                if (pinnedData.isNotEmpty) ...[
-                  SizedBox(
-                    height: _pinnedDataHeight(constraints),
-                    child: Scrollbar(
-                      thumbVisibility: true,
-                      controller: pinnedScrollController,
-                      child: ListView.builder(
-                        controller: pinnedScrollController,
-                        itemCount: pinnedData.length,
-                        itemExtent: widget.rowItemExtent,
-                        itemBuilder: (context, index) =>
-                            _buildItem(context, index, isPinned: true),
+        return Scrollbar(
+          controller: _horizontalScrollbarController,
+          thumbVisibility: true,
+          child: SingleChildScrollView(
+            scrollDirection: Axis.horizontal,
+            controller: _horizontalScrollbarController,
+            child: SelectionArea(
+              child: SizedBox(
+                width: max(viewWidth, _tableWidthForOriginalColumns),
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.stretch,
+                  children: [
+                    if (showColumnGroupHeader)
+                      TableRow<T>.tableColumnGroupHeader(
+                        columnGroups: columnGroups,
+                        columnWidths: adjustedColumnWidths,
+                        sortColumn: sortColumn,
+                        sortDirection: tableUiState.sortDirection,
+                        secondarySortColumn:
+                            widget.tableController.secondarySortColumn,
+                        onSortChanged: widget.tableController.sortDataAndNotify,
+                        tall: widget.tallHeaders,
+                        backgroundColor: widget.headerColor,
                       ),
+                    // TODO(kenz): add support for excluding column headers.
+                    TableRow<T>.tableColumnHeader(
+                      key: const Key('Table header'),
+                      columns: widget.tableController.columns,
+                      columnGroups: columnGroups,
+                      columnWidths: adjustedColumnWidths,
+                      sortColumn: sortColumn,
+                      sortDirection: tableUiState.sortDirection,
+                      secondarySortColumn:
+                          widget.tableController.secondarySortColumn,
+                      onSortChanged: widget.tableController.sortDataAndNotify,
+                      tall: widget.tallHeaders,
+                      backgroundColor: widget.headerColor,
                     ),
-                  ),
-                  const ThickDivider(),
-                ],
-                Expanded(
-                  child: Scrollbar(
-                    thumbVisibility: true,
-                    controller: scrollController,
-                    child: GestureDetector(
-                      behavior: HitTestBehavior.translucent,
-                      onTapDown: (a) => widget.focusNode?.requestFocus(),
-                      child: Focus(
-                        autofocus: true,
-                        onKeyEvent: (_, event) => widget.handleKeyEvent != null
-                            ? widget.handleKeyEvent!(
-                                event,
-                                scrollController,
-                                constraints,
-                              )
-                            : KeyEventResult.ignored,
-                        focusNode: widget.focusNode,
-                        child: ListView.builder(
-                          controller: scrollController,
-                          itemCount: _dataRowCount(
-                            constraints,
-                            showColumnGroupHeader,
+                    if (pinnedData.isNotEmpty) ...[
+                      SizedBox(
+                        height: _pinnedDataHeight(constraints),
+                        child: Scrollbar(
+                          thumbVisibility: true,
+                          controller: pinnedScrollController,
+                          child: ListView.builder(
+                            controller: pinnedScrollController,
+                            itemCount: pinnedData.length,
+                            itemExtent: widget.rowItemExtent,
+                            itemBuilder: (context, index) =>
+                                _buildItem(context, index, isPinned: true),
                           ),
-                          itemExtent: widget.rowItemExtent,
-                          itemBuilder: _buildItem,
+                        ),
+                      ),
+                      const ThickDivider(),
+                    ],
+                    Expanded(
+                      child: Scrollbar(
+                        thumbVisibility: true,
+                        controller: scrollController,
+                        child: GestureDetector(
+                          behavior: HitTestBehavior.translucent,
+                          onTapDown: (a) => widget.focusNode?.requestFocus(),
+                          child: Focus(
+                            autofocus: true,
+                            onKeyEvent: (_, event) =>
+                                widget.handleKeyEvent != null
+                                ? widget.handleKeyEvent!(
+                                    event,
+                                    scrollController,
+                                    constraints,
+                                  )
+                                : KeyEventResult.ignored,
+                            focusNode: widget.focusNode,
+                            child: ListView.builder(
+                              controller: scrollController,
+                              itemCount: _dataRowCount(
+                                constraints,
+                                showColumnGroupHeader,
+                              ),
+                              itemExtent: widget.rowItemExtent,
+                              itemBuilder: _buildItem,
+                            ),
+                          ),
                         ),
                       ),
                     ),
-                  ),
+                  ],
                 ),
-              ],
+              ),
             ),
           ),
         );
diff --git a/packages/devtools_app/lib/src/shared/table/table_controller.dart b/packages/devtools_app/lib/src/shared/table/table_controller.dart
index 256b546..c7945e8 100644
--- a/packages/devtools_app/lib/src/shared/table/table_controller.dart
+++ b/packages/devtools_app/lib/src/shared/table/table_controller.dart
@@ -277,10 +277,13 @@
 
   ScrollController? verticalScrollController;
 
+  ScrollController? horizontalScrollController;
+
   void initScrollController([double initialScrollOffset = 0.0]) {
     verticalScrollController = ScrollController(
       initialScrollOffset: initialScrollOffset,
     );
+    horizontalScrollController = ScrollController();
   }
 
   void storeScrollPosition() {
@@ -357,6 +360,8 @@
   void dispose() {
     verticalScrollController?.dispose();
     verticalScrollController = null;
+    horizontalScrollController?.dispose();
+    horizontalScrollController = null;
     _tableData.dispose();
     super.dispose();
   }
diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
index 73e804c..76c08ac 100644
--- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
+++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
@@ -15,7 +15,8 @@
 
 ## General updates
 
-TODO: Remove this section if there are not any general updates.
+- Added a horizontal scrollbar to data tables to help with navigation.  -
+  [#9482](https://github.com/flutter/devtools/pull/9482)
 
 ## Inspector updates
 
diff --git a/packages/devtools_app/test/shared/table/table_test.dart b/packages/devtools_app/test/shared/table/table_test.dart
index 88b6237..b2303f4 100644
--- a/packages/devtools_app/test/shared/table/table_test.dart
+++ b/packages/devtools_app/test/shared/table/table_test.dart
@@ -1379,32 +1379,34 @@
       }
     });
 
-    testWidgets('properly collapses and expands the tree', (
-      WidgetTester tester,
-    ) async {
-      final table = TreeTable<TestData>(
-        columns: [_NumberColumn(), treeColumn],
-        dataRoots: [tree1],
-        dataKey: 'test-data',
-        treeColumn: treeColumn,
-        keyFactory: (d) => Key(d.name),
-        defaultSortColumn: treeColumn,
-        defaultSortDirection: SortDirection.ascending,
-      );
-      await tester.pumpWidget(wrap(table));
-      await tester.pumpAndSettle();
+    testWidgetsWithWindowSize(
+      'properly collapses and expands the tree',
+      windowSize,
+      (WidgetTester tester) async {
+        final table = TreeTable<TestData>(
+          columns: [_NumberColumn(), treeColumn],
+          dataRoots: [tree1],
+          dataKey: 'test-data',
+          treeColumn: treeColumn,
+          keyFactory: (d) => Key(d.name),
+          defaultSortColumn: treeColumn,
+          defaultSortDirection: SortDirection.ascending,
+        );
+        await tester.pumpWidget(wrap(table));
+        await tester.pumpAndSettle();
 
-      expect(tree1.isExpanded, true);
-      await tester.tap(find.byKey(const Key('Foo')));
-      await tester.pumpAndSettle();
-      expect(tree1.isExpanded, false);
-      await tester.tap(find.byKey(const Key('Foo')));
-      await tester.pumpAndSettle();
-      expect(tree1.isExpanded, true);
-      await tester.tap(find.byKey(const Key('Bar')));
-      await tester.pumpAndSettle();
-      expect(tree1.children[0].isExpanded, false);
-    });
+        expect(tree1.isExpanded, true);
+        await tester.tap(find.byKey(const Key('Foo')));
+        await tester.pumpAndSettle();
+        expect(tree1.isExpanded, false);
+        await tester.tap(find.byKey(const Key('Foo')));
+        await tester.pumpAndSettle();
+        expect(tree1.isExpanded, true);
+        await tester.tap(find.byKey(const Key('Bar')));
+        await tester.pumpAndSettle();
+        expect(tree1.children[0].isExpanded, false);
+      },
+    );
 
     testWidgets('starts with sorted data', (WidgetTester tester) async {
       expect(tree1.children[0].name, 'Bar');
@@ -1569,85 +1571,87 @@
       });
     });
 
-    testWidgets('properly colors rows with alternating colors', (
-      WidgetTester tester,
-    ) async {
-      final data = TestData('Foo', 0)
-        ..children.addAll([
-          TestData('Bar', 1)
-            ..children.addAll([
-              TestData('Baz', 2),
-              TestData('Qux', 3),
-              TestData('Snap', 4),
-            ]),
-          TestData('Crackle', 5),
-        ])
-        ..expandCascading();
-      final table = TreeTable<TestData>(
-        columns: [_NumberColumn(), treeColumn],
-        dataRoots: [data],
-        dataKey: 'test-data',
-        treeColumn: treeColumn,
-        keyFactory: (d) => Key(d.name),
-        defaultSortColumn: treeColumn,
-        defaultSortDirection: SortDirection.ascending,
-      );
+    testWidgetsWithWindowSize(
+      'properly colors rows with alternating colors',
+      windowSize,
+      (WidgetTester tester) async {
+        final data = TestData('Foo', 0)
+          ..children.addAll([
+            TestData('Bar', 1)
+              ..children.addAll([
+                TestData('Baz', 2),
+                TestData('Qux', 3),
+                TestData('Snap', 4),
+              ]),
+            TestData('Crackle', 5),
+          ])
+          ..expandCascading();
+        final table = TreeTable<TestData>(
+          columns: [_NumberColumn(), treeColumn],
+          dataRoots: [data],
+          dataKey: 'test-data',
+          treeColumn: treeColumn,
+          keyFactory: (d) => Key(d.name),
+          defaultSortColumn: treeColumn,
+          defaultSortDirection: SortDirection.ascending,
+        );
 
-      final fooFinder = find.byKey(const Key('Foo'));
-      final barFinder = find.byKey(const Key('Bar'));
-      final bazFinder = find.byKey(const Key('Baz'));
-      final quxFinder = find.byKey(const Key('Qux'));
-      final snapFinder = find.byKey(const Key('Snap'));
-      final crackleFinder = find.byKey(const Key('Crackle'));
+        final fooFinder = find.byKey(const Key('Foo'));
+        final barFinder = find.byKey(const Key('Bar'));
+        final bazFinder = find.byKey(const Key('Baz'));
+        final quxFinder = find.byKey(const Key('Qux'));
+        final snapFinder = find.byKey(const Key('Snap'));
+        final crackleFinder = find.byKey(const Key('Crackle'));
 
-      // Expected ARGB color values.
-      const color1Value = '(a: 1.0, r: 0.94, g: 0.94, b: 0.94)';
-      const color2Value = '(a: 1.0, r: 1.0, g: 1.0, b: 1.0)';
-      const rowSelectedColorValue = '(a: 1.0, r: 1.0, g: 1.0, b: 1.0)';
+        // Expected ARGB color values.
+        const color1Value = '(a: 1.0, r: 0.94, g: 0.94, b: 0.94)';
+        const color2Value = '(a: 1.0, r: 1.0, g: 1.0, b: 1.0)';
+        const rowSelectedColorValue = '(a: 1.0, r: 1.0, g: 1.0, b: 1.0)';
 
-      await tester.pumpWidget(wrap(table));
-      await tester.pumpAndSettle();
-      expect(tree1.isExpanded, true);
+        await tester.pumpWidget(wrap(table));
+        await tester.pumpAndSettle();
+        expect(tree1.isExpanded, true);
 
-      expect(fooFinder, findsOneWidget);
-      expect(barFinder, findsOneWidget);
-      expect(bazFinder, findsOneWidget);
-      expect(quxFinder, findsOneWidget);
-      expect(snapFinder, findsOneWidget);
-      expect(crackleFinder, findsOneWidget);
-      TableRow fooRow = tester.widget(fooFinder);
-      TableRow barRow = tester.widget(barFinder);
-      final TableRow bazRow = tester.widget(bazFinder);
-      final TableRow quxRow = tester.widget(quxFinder);
-      final TableRow snapRow = tester.widget(snapFinder);
-      TableRow crackleRow = tester.widget(crackleFinder);
+        expect(fooFinder, findsOneWidget);
+        expect(barFinder, findsOneWidget);
+        expect(bazFinder, findsOneWidget);
+        expect(quxFinder, findsOneWidget);
+        expect(snapFinder, findsOneWidget);
+        expect(crackleFinder, findsOneWidget);
+        TableRow fooRow = tester.widget(fooFinder);
+        TableRow barRow = tester.widget(barFinder);
+        final TableRow bazRow = tester.widget(bazFinder);
+        final TableRow quxRow = tester.widget(quxFinder);
+        final TableRow snapRow = tester.widget(snapFinder);
+        TableRow crackleRow = tester.widget(crackleFinder);
 
-      expect(fooRow.backgroundColor!.toArgbString(), color1Value);
-      expect(barRow.backgroundColor!.toArgbString(), color2Value);
-      expect(bazRow.backgroundColor!.toArgbString(), color1Value);
-      expect(quxRow.backgroundColor!.toArgbString(), color2Value);
-      expect(snapRow.backgroundColor!.toArgbString(), color1Value);
-      expect(crackleRow.backgroundColor!.toArgbString(), color2Value);
+        expect(fooRow.backgroundColor!.toArgbString(), color1Value);
+        expect(barRow.backgroundColor!.toArgbString(), color2Value);
+        expect(bazRow.backgroundColor!.toArgbString(), color1Value);
+        expect(quxRow.backgroundColor!.toArgbString(), color2Value);
+        expect(snapRow.backgroundColor!.toArgbString(), color1Value);
+        expect(crackleRow.backgroundColor!.toArgbString(), color2Value);
 
-      await tester.tap(barFinder);
-      await tester.pumpAndSettle();
-      expect(fooFinder, findsOneWidget);
-      expect(barFinder, findsOneWidget);
-      expect(bazFinder, findsNothing);
-      expect(quxFinder, findsNothing);
-      expect(snapFinder, findsNothing);
-      expect(crackleFinder, findsOneWidget);
-      fooRow = tester.widget(fooFinder);
-      barRow = tester.widget(barFinder);
-      crackleRow = tester.widget(crackleFinder);
+        await tester.tap(barFinder);
+        await tester.pumpAndSettle();
+        expect(fooFinder, findsOneWidget);
+        expect(barFinder, findsOneWidget);
+        expect(bazFinder, findsNothing);
+        expect(quxFinder, findsNothing);
+        expect(snapFinder, findsNothing);
+        expect(crackleFinder, findsOneWidget);
+        fooRow = tester.widget(fooFinder);
+        barRow = tester.widget(barFinder);
+        crackleRow = tester.widget(crackleFinder);
 
-      expect(fooRow.backgroundColor!.toArgbString(), color1Value);
-      // [barRow] has the rowSelected color after being tapped.
-      expect(barRow.backgroundColor!.toArgbString(), rowSelectedColorValue);
-      // [crackleRow] has a different background color after collapsing previous
-      // row (Bar).
-      expect(crackleRow.backgroundColor!.toArgbString(), color1Value);
-    });
+        expect(fooRow.backgroundColor!.toArgbString(), color1Value);
+        // [barRow] has the rowSelected color after being tapped.
+        expect(barRow.backgroundColor!.toArgbString(), rowSelectedColorValue);
+        // [crackleRow] has a different background color after collapsing previous
+        // row (Bar).
+        expect(crackleRow.backgroundColor!.toArgbString(), color1Value);
+      },
+    );
 
     test('fails when TreeColumn is not in column list', () {
       expect(() {
diff --git a/packages/devtools_app/test/test_infra/goldens/memory/load_offline_data_trace_tab.png b/packages/devtools_app/test/test_infra/goldens/memory/load_offline_data_trace_tab.png
index bacc8c8..21eb64c 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory/load_offline_data_trace_tab.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory/load_offline_data_trace_tab.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_empty1.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_empty1.png
index 3952622..869ff8e 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_empty1.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_empty1.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_empty2.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_empty2.png
index 3952622..869ff8e 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_empty2.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_empty2.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_selected_class.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_selected_class.png
index 15e5212..67d1d9f 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_selected_class.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_selected_class.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_diff.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_diff.png
index bac036c..b34779c 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_diff.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_diff.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_single.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_single.png
index 282a6cb..cf36edd 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_single.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_except_single.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_diff.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_diff.png
index bac036c..b34779c 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_diff.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_diff.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_single.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_single.png
index 282a6cb..cf36edd 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_single.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_scene_single.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_diff.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_diff.png
index bac036c..b34779c 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_diff.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_diff.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_single.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_single.png
index 282a6cb..cf36edd 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_single.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_snapshot_showAll_single.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots1.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots1.png
index 15e5212..67d1d9f 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots1.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots1.png
Binary files differ
diff --git a/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots2.png b/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots2.png
index 15e5212..67d1d9f 100644
--- a/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots2.png
+++ b/packages/devtools_app/test/test_infra/goldens/memory_diff_three_snapshots2.png
Binary files differ