Skip to content

Commit a7942e8

Browse files
authored
Add convenience constructors for SliverList (#116605)
* init * lint * add the other two slivers * fix lint * add test for sliverlist.separated * add3 more * fix lint and tests * remove trailing spaces * remove trailing spaces 2 * fix lint * fix lint again
1 parent bd69ef7 commit a7942e8

File tree

4 files changed

+705
-1
lines changed

4 files changed

+705
-1
lines changed

packages/flutter/lib/src/widgets/sliver.dart

+289
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'dart:collection' show HashMap, SplayTreeMap;
6+
import 'dart:math' as math;
67

78
import 'package:flutter/foundation.dart';
89
import 'package:flutter/rendering.dart';
@@ -1035,6 +1036,184 @@ class SliverList extends SliverMultiBoxAdaptorWidget {
10351036
required super.delegate,
10361037
});
10371038

1039+
/// A sliver that places multiple box children in a linear array along the main
1040+
/// axis.
1041+
///
1042+
/// This constructor is appropriate for sliver lists with a large (or
1043+
/// infinite) number of children because the builder is called only for those
1044+
/// children that are actually visible.
1045+
///
1046+
/// Providing a non-null `itemCount` improves the ability of the [SliverGrid]
1047+
/// to estimate the maximum scroll extent.
1048+
///
1049+
/// `itemBuilder` will be called only with indices greater than or equal to
1050+
/// zero and less than `itemCount`.
1051+
///
1052+
/// {@macro flutter.widgets.ListView.builder.itemBuilder}
1053+
///
1054+
/// {@macro flutter.widgets.PageView.findChildIndexCallback}
1055+
///
1056+
/// The `addAutomaticKeepAlives` argument corresponds to the
1057+
/// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The
1058+
/// `addRepaintBoundaries` argument corresponds to the
1059+
/// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The
1060+
/// `addSemanticIndexes` argument corresponds to the
1061+
/// [SliverChildBuilderDelegate.addSemanticIndexes] property.
1062+
///
1063+
/// {@tool snippet}
1064+
/// This example, which would be inserted into a [CustomScrollView.slivers]
1065+
/// list, shows an infinite number of items in varying shades of blue:
1066+
///
1067+
/// ```dart
1068+
/// SliverList.builder(
1069+
/// itemBuilder: (BuildContext context, int index) {
1070+
/// return Container(
1071+
/// alignment: Alignment.center,
1072+
/// color: Colors.lightBlue[100 * (index % 9)],
1073+
/// child: Text('list item $index'),
1074+
/// );
1075+
/// },
1076+
/// )
1077+
/// ```
1078+
/// {@end-tool}
1079+
SliverList.builder({
1080+
super.key,
1081+
required NullableIndexedWidgetBuilder itemBuilder,
1082+
ChildIndexGetter? findChildIndexCallback,
1083+
int? itemCount,
1084+
bool addAutomaticKeepAlives = true,
1085+
bool addRepaintBoundaries = true,
1086+
bool addSemanticIndexes = true,
1087+
}) : super(delegate: SliverChildBuilderDelegate(
1088+
itemBuilder,
1089+
findChildIndexCallback: findChildIndexCallback,
1090+
childCount: itemCount,
1091+
addAutomaticKeepAlives: addAutomaticKeepAlives,
1092+
addRepaintBoundaries: addRepaintBoundaries,
1093+
addSemanticIndexes: addSemanticIndexes,
1094+
));
1095+
1096+
/// A sliver that places multiple box children, separated by box widgets, in a linear array along the main
1097+
/// axis.
1098+
///
1099+
/// This constructor is appropriate for sliver lists with a large (or
1100+
/// infinite) number of children because the builder is called only for those
1101+
/// children that are actually visible.
1102+
///
1103+
/// Providing a non-null `itemCount` improves the ability of the [SliverGrid]
1104+
/// to estimate the maximum scroll extent.
1105+
///
1106+
/// `itemBuilder` will be called only with indices greater than or equal to
1107+
/// zero and less than `itemCount`.
1108+
///
1109+
/// {@macro flutter.widgets.ListView.builder.itemBuilder}
1110+
///
1111+
/// {@macro flutter.widgets.PageView.findChildIndexCallback}
1112+
///
1113+
///
1114+
/// The `separatorBuilder` is similar to `itemBuilder`, except it is the widget
1115+
/// that gets placed between itemBuilder(context, index) and itemBuilder(context, index + 1).
1116+
///
1117+
/// The `addAutomaticKeepAlives` argument corresponds to the
1118+
/// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The
1119+
/// `addRepaintBoundaries` argument corresponds to the
1120+
/// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The
1121+
/// `addSemanticIndexes` argument corresponds to the
1122+
/// [SliverChildBuilderDelegate.addSemanticIndexes] property.
1123+
/// {@tool snippet}
1124+
///
1125+
/// This example shows how to create a [SliverList] whose [Container] items
1126+
/// are separated by [Divider]s.
1127+
///
1128+
/// ```dart
1129+
/// SliverList.separated(
1130+
/// itemBuilder: (BuildContext context, int index) {
1131+
/// return Container(
1132+
/// alignment: Alignment.center,
1133+
/// color: Colors.lightBlue[100 * (index % 9)],
1134+
/// child: Text('list item $index'),
1135+
/// );
1136+
/// },
1137+
/// separatorBuilder: (BuildContext context, int index) => const Divider(),
1138+
/// )
1139+
/// ```
1140+
/// {@end-tool}
1141+
SliverList.separated({
1142+
super.key,
1143+
required NullableIndexedWidgetBuilder itemBuilder,
1144+
ChildIndexGetter? findChildIndexCallback,
1145+
required NullableIndexedWidgetBuilder separatorBuilder,
1146+
int? itemCount,
1147+
bool addAutomaticKeepAlives = true,
1148+
bool addRepaintBoundaries = true,
1149+
bool addSemanticIndexes = true,
1150+
}) : assert(itemBuilder != null),
1151+
assert(separatorBuilder != null),
1152+
super(delegate: SliverChildBuilderDelegate(
1153+
(BuildContext context, int index) {
1154+
final int itemIndex = index ~/ 2;
1155+
final Widget? widget;
1156+
if (index.isEven) {
1157+
widget = itemBuilder(context, itemIndex);
1158+
} else {
1159+
widget = separatorBuilder(context, itemIndex);
1160+
assert(() {
1161+
if (widget == null) {
1162+
throw FlutterError('separatorBuilder cannot return null.');
1163+
}
1164+
return true;
1165+
}());
1166+
}
1167+
return widget;
1168+
},
1169+
findChildIndexCallback: findChildIndexCallback,
1170+
childCount: itemCount == null ? null : math.max(0, itemCount * 2 - 1),
1171+
addAutomaticKeepAlives: addAutomaticKeepAlives,
1172+
addRepaintBoundaries: addRepaintBoundaries,
1173+
addSemanticIndexes: addSemanticIndexes,
1174+
semanticIndexCallback: (Widget _, int index) {
1175+
return index.isEven ? index ~/ 2 : null;
1176+
},
1177+
));
1178+
1179+
/// A sliver that places multiple box children in a linear array along the main
1180+
/// axis.
1181+
///
1182+
/// This constructor uses a list of [Widget]s to build the sliver.
1183+
///
1184+
/// The `addAutomaticKeepAlives` argument corresponds to the
1185+
/// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The
1186+
/// `addRepaintBoundaries` argument corresponds to the
1187+
/// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The
1188+
/// `addSemanticIndexes` argument corresponds to the
1189+
/// [SliverChildBuilderDelegate.addSemanticIndexes] property.
1190+
///
1191+
/// {@tool snippet}
1192+
/// This example, which would be inserted into a [CustomScrollView.slivers]
1193+
/// list, shows an infinite number of items in varying shades of blue:
1194+
///
1195+
/// ```dart
1196+
/// SliverList.list(
1197+
/// children: const <Widget>[
1198+
/// Text('Hello'),
1199+
/// Text('World!'),
1200+
/// ],
1201+
/// );
1202+
/// ```
1203+
/// {@end-tool}
1204+
SliverList.list({
1205+
super.key,
1206+
required List<Widget> children,
1207+
bool addAutomaticKeepAlives = true,
1208+
bool addRepaintBoundaries = true,
1209+
bool addSemanticIndexes = true,
1210+
}) : super(delegate: SliverChildListDelegate(
1211+
children,
1212+
addAutomaticKeepAlives: addAutomaticKeepAlives,
1213+
addRepaintBoundaries: addRepaintBoundaries,
1214+
addSemanticIndexes: addSemanticIndexes,
1215+
));
1216+
10381217
@override
10391218
SliverMultiBoxAdaptorElement createElement() => SliverMultiBoxAdaptorElement(this, replaceMovedChildren: true);
10401219

@@ -1098,6 +1277,116 @@ class SliverFixedExtentList extends SliverMultiBoxAdaptorWidget {
10981277
required this.itemExtent,
10991278
});
11001279

1280+
/// A sliver that places multiple box children in a linear array along the main
1281+
/// axis.
1282+
///
1283+
/// [SliverFixedExtentList] places its children in a linear array along the main
1284+
/// axis starting at offset zero and without gaps. Each child is forced to have
1285+
/// the [itemExtent] in the main axis and the
1286+
/// [SliverConstraints.crossAxisExtent] in the cross axis.
1287+
///
1288+
/// This constructor is appropriate for sliver lists with a large (or
1289+
/// infinite) number of children whose extent is already determined.
1290+
///
1291+
/// Providing a non-null `itemCount` improves the ability of the [SliverGrid]
1292+
/// to estimate the maximum scroll extent.
1293+
///
1294+
/// `itemBuilder` will be called only with indices greater than or equal to
1295+
/// zero and less than `itemCount`.
1296+
///
1297+
/// {@macro flutter.widgets.ListView.builder.itemBuilder}
1298+
///
1299+
/// The `itemExtent` argument is the extent of each item.
1300+
///
1301+
/// {@macro flutter.widgets.PageView.findChildIndexCallback}
1302+
///
1303+
/// The `addAutomaticKeepAlives` argument corresponds to the
1304+
/// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The
1305+
/// `addRepaintBoundaries` argument corresponds to the
1306+
/// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The
1307+
/// `addSemanticIndexes` argument corresponds to the
1308+
/// [SliverChildBuilderDelegate.addSemanticIndexes] property.
1309+
/// {@tool snippet}
1310+
///
1311+
/// This example, which would be inserted into a [CustomScrollView.slivers]
1312+
/// list, shows an infinite number of items in varying shades of blue:
1313+
///
1314+
/// ```dart
1315+
/// SliverFixedExtentList.builder(
1316+
/// itemExtent: 50.0,
1317+
/// itemBuilder: (BuildContext context, int index) {
1318+
/// return Container(
1319+
/// alignment: Alignment.center,
1320+
/// color: Colors.lightBlue[100 * (index % 9)],
1321+
/// child: Text('list item $index'),
1322+
/// );
1323+
/// },
1324+
/// )
1325+
/// ```
1326+
/// {@end-tool}
1327+
SliverFixedExtentList.builder({
1328+
super.key,
1329+
required NullableIndexedWidgetBuilder itemBuilder,
1330+
required this.itemExtent,
1331+
ChildIndexGetter? findChildIndexCallback,
1332+
int? itemCount,
1333+
bool addAutomaticKeepAlives = true,
1334+
bool addRepaintBoundaries = true,
1335+
bool addSemanticIndexes = true,
1336+
}) : super(delegate: SliverChildBuilderDelegate(
1337+
itemBuilder,
1338+
findChildIndexCallback: findChildIndexCallback,
1339+
childCount: itemCount,
1340+
addAutomaticKeepAlives: addAutomaticKeepAlives,
1341+
addRepaintBoundaries: addRepaintBoundaries,
1342+
addSemanticIndexes: addSemanticIndexes,
1343+
));
1344+
1345+
/// A sliver that places multiple box children in a linear array along the main
1346+
/// axis.
1347+
///
1348+
/// [SliverFixedExtentList] places its children in a linear array along the main
1349+
/// axis starting at offset zero and without gaps. Each child is forced to have
1350+
/// the [itemExtent] in the main axis and the
1351+
/// [SliverConstraints.crossAxisExtent] in the cross axis.
1352+
///
1353+
/// This constructor uses a list of [Widget]s to build the sliver.
1354+
///
1355+
/// The `addAutomaticKeepAlives` argument corresponds to the
1356+
/// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The
1357+
/// `addRepaintBoundaries` argument corresponds to the
1358+
/// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The
1359+
/// `addSemanticIndexes` argument corresponds to the
1360+
/// [SliverChildBuilderDelegate.addSemanticIndexes] property.
1361+
///
1362+
/// {@tool snippet}
1363+
/// This example, which would be inserted into a [CustomScrollView.slivers]
1364+
/// list, shows an infinite number of items in varying shades of blue:
1365+
///
1366+
/// ```dart
1367+
/// SliverFixedExtentList.list(
1368+
/// itemExtent: 50.0,
1369+
/// children: const <Widget>[
1370+
/// Text('Hello'),
1371+
/// Text('World!'),
1372+
/// ],
1373+
/// );
1374+
/// ```
1375+
/// {@end-tool}
1376+
SliverFixedExtentList.list({
1377+
super.key,
1378+
required List<Widget> children,
1379+
required this.itemExtent,
1380+
bool addAutomaticKeepAlives = true,
1381+
bool addRepaintBoundaries = true,
1382+
bool addSemanticIndexes = true,
1383+
}) : super(delegate: SliverChildListDelegate(
1384+
children,
1385+
addAutomaticKeepAlives: addAutomaticKeepAlives,
1386+
addRepaintBoundaries: addRepaintBoundaries,
1387+
addSemanticIndexes: addSemanticIndexes,
1388+
));
1389+
11011390
/// The extent the children are forced to have in the main axis.
11021391
final double itemExtent;
11031392

0 commit comments

Comments
 (0)