Skip to content

Commit 0ff0aff

Browse files
authored
Expose controller for PaginatedDataTable (#100005)
1 parent 89f755c commit 0ff0aff

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

packages/flutter/lib/src/material/paginated_data_table.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ class PaginatedDataTable extends StatefulWidget {
8686
this.arrowHeadColor,
8787
required this.source,
8888
this.checkboxHorizontalMargin,
89+
this.controller,
90+
this.primary,
8991
}) : assert(actions == null || (actions != null && header != null)),
9092
assert(columns != null),
9193
assert(dragStartBehavior != null),
@@ -105,7 +107,11 @@ class PaginatedDataTable extends StatefulWidget {
105107
assert(availableRowsPerPage != null && availableRowsPerPage.contains(rowsPerPage));
106108
return true;
107109
}()),
108-
assert(source != null);
110+
assert(source != null),
111+
assert(!(controller != null && (primary ?? false)),
112+
'Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. '
113+
'You cannot both set primary to true and pass an explicit controller.',
114+
);
109115

110116
/// The table card's optional header.
111117
///
@@ -237,6 +243,12 @@ class PaginatedDataTable extends StatefulWidget {
237243
/// Defines the color of the arrow heads in the footer.
238244
final Color? arrowHeadColor;
239245

246+
/// {@macro flutter.widgets.scroll_view.controller}
247+
final ScrollController? controller;
248+
249+
/// {@macro flutter.widgets.scroll_view.primary}
250+
final bool? primary;
251+
240252
@override
241253
PaginatedDataTableState createState() => PaginatedDataTableState();
242254
}
@@ -501,6 +513,8 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
501513
),
502514
SingleChildScrollView(
503515
scrollDirection: Axis.horizontal,
516+
primary: widget.primary,
517+
controller: widget.controller,
504518
dragStartBehavior: widget.dragStartBehavior,
505519
child: ConstrainedBox(
506520
constraints: BoxConstraints(minWidth: constraints.minWidth),

packages/flutter/test/material/paginated_data_table_test.dart

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ void main() {
398398
expect(find.text('Rows per page:'), findsOneWidget);
399399
expect(tester.getTopLeft(find.text('Rows per page:')).dx, 18.0); // 14 padding in the footer row, 4 padding from the card
400400
});
401+
401402
testWidgets('PaginatedDataTable custom row height', (WidgetTester tester) async {
402403
final TestDataSource source = TestDataSource();
403404

@@ -1043,4 +1044,85 @@ void main() {
10431044
await tester.pumpWidget(buildFrame(overflowBar));
10441045
expect(headerX, tester.getTopLeft(find.byType(ElevatedButton)).dx);
10451046
});
1047+
1048+
testWidgets('PaginatedDataTable can be scrolled using ScrollController', (WidgetTester tester) async {
1049+
final TestDataSource source = TestDataSource();
1050+
final ScrollController scrollController = ScrollController();
1051+
1052+
Widget buildTable(TestDataSource source) {
1053+
return Align(
1054+
alignment: Alignment.topLeft,
1055+
child: SizedBox(
1056+
width: 100,
1057+
child: PaginatedDataTable(
1058+
controller: scrollController,
1059+
header: const Text('Test table'),
1060+
source: source,
1061+
rowsPerPage: 2,
1062+
columns: const <DataColumn>[
1063+
DataColumn(
1064+
label: Text('Name'),
1065+
tooltip: 'Name',
1066+
),
1067+
DataColumn(
1068+
label: Text('Calories'),
1069+
tooltip: 'Calories',
1070+
numeric: true,
1071+
),
1072+
DataColumn(
1073+
label: Text('Generation'),
1074+
tooltip: 'Generation',
1075+
),
1076+
],
1077+
),
1078+
),
1079+
);
1080+
}
1081+
1082+
await tester.pumpWidget(MaterialApp(
1083+
home: buildTable(source),
1084+
));
1085+
1086+
// DataTable uses provided ScrollController
1087+
final Scrollable bodyScrollView = tester.widget(find.byType(Scrollable).first);
1088+
expect(bodyScrollView.controller, scrollController);
1089+
1090+
expect(scrollController.offset, 0.0);
1091+
scrollController.jumpTo(50.0);
1092+
await tester.pumpAndSettle();
1093+
1094+
expect(scrollController.offset, 50.0);
1095+
});
1096+
1097+
testWidgets('PaginatedDataTable uses PrimaryScrollController when primary ', (WidgetTester tester) async {
1098+
final ScrollController primaryScrollController = ScrollController();
1099+
final TestDataSource source = TestDataSource();
1100+
1101+
await tester.pumpWidget(
1102+
MaterialApp(
1103+
home: PrimaryScrollController(
1104+
controller: primaryScrollController,
1105+
child: PaginatedDataTable(
1106+
primary: true,
1107+
header: const Text('Test table'),
1108+
source: source,
1109+
rowsPerPage: 2,
1110+
columns: const <DataColumn>[
1111+
DataColumn(label: Text('Name')),
1112+
DataColumn(label: Text('Calories'), numeric: true),
1113+
DataColumn(label: Text('Generation')),
1114+
],
1115+
),
1116+
),
1117+
)
1118+
);
1119+
1120+
// DataTable uses primaryScrollController
1121+
final Scrollable bodyScrollView = tester.widget(find.byType(Scrollable).first);
1122+
expect(bodyScrollView.controller, primaryScrollController);
1123+
1124+
// Footer does not use primaryScrollController
1125+
final Scrollable footerScrollView = tester.widget(find.byType(Scrollable).last);
1126+
expect(footerScrollView.controller, null);
1127+
});
10461128
}

0 commit comments

Comments
 (0)