ListView.custom constructor Null safety

const ListView.custom(
  1. {Key? key,
  2. Axis scrollDirection = Axis.vertical,
  3. bool reverse = false,
  4. ScrollController? controller,
  5. bool? primary,
  6. ScrollPhysics? physics,
  7. bool shrinkWrap = false,
  8. EdgeInsetsGeometry? padding,
  9. double? itemExtent,
  10. Widget? prototypeItem,
  11. required SliverChildDelegate childrenDelegate,
  12. double? cacheExtent,
  13. int? semanticChildCount,
  14. DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  15. ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
  16. String? restorationId,
  17. Clip clipBehavior = Clip.hardEdge}
)

Creates a scrollable, linear array of widgets with a custom child model.

For example, a custom child model can control the algorithm used to estimate the size of children that are not actually visible.

This ListView uses a custom SliverChildBuilderDelegate to support child reordering.
class MyListView extends StatefulWidget {
  const MyListView({Key? key}) : super(key: key);

  @override
  State<MyListView> createState() => _MyListViewState();
}

class _MyListViewState extends State<MyListView> {
  List<String> items = <String>['1', '2', '3', '4', '5'];

  void _reverse() {
    setState(() {
      items = items.reversed.toList();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: ListView.custom(
          childrenDelegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              return KeepAlive(
                data: items[index],
                key: ValueKey<String>(items[index]),
              );
            },
            childCount: items.length,
            findChildIndexCallback: (Key key) {
              final ValueKey<String> valueKey = key as ValueKey<String>;
              final String data = valueKey.value;
              return items.indexOf(data);
            }
          ),
        ),
      ),
      bottomNavigationBar: BottomAppBar(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextButton(
              onPressed: () => _reverse(),
              child: const Text('Reverse items'),
            ),
          ],
        ),
      ),
    );
  }
}

class KeepAlive extends StatefulWidget {
  const KeepAlive({
    required Key key,
    required this.data,
  }) : super(key: key);

  final String data;

  @override
  State<KeepAlive> createState() => _KeepAliveState();
}

class _KeepAliveState extends State<KeepAlive> with AutomaticKeepAliveClientMixin{
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Text(widget.data);
  }
}

Implementation

const ListView.custom({
  Key? key,
  Axis scrollDirection = Axis.vertical,
  bool reverse = false,
  ScrollController? controller,
  bool? primary,
  ScrollPhysics? physics,
  bool shrinkWrap = false,
  EdgeInsetsGeometry? padding,
  this.itemExtent,
  this.prototypeItem,
  required this.childrenDelegate,
  double? cacheExtent,
  int? semanticChildCount,
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
  ScrollViewKeyboardDismissBehavior keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
  String? restorationId,
  Clip clipBehavior = Clip.hardEdge,
}) : assert(childrenDelegate != null),
     assert(
       itemExtent == null || prototypeItem == null,
       'You can only pass itemExtent or prototypeItem, not both',
     ),
     super(
       key: key,
       scrollDirection: scrollDirection,
       reverse: reverse,
       controller: controller,
       primary: primary,
       physics: physics,
       shrinkWrap: shrinkWrap,
       padding: padding,
       cacheExtent: cacheExtent,
       semanticChildCount: semanticChildCount,
       dragStartBehavior: dragStartBehavior,
       keyboardDismissBehavior: keyboardDismissBehavior,
       restorationId: restorationId,
       clipBehavior: clipBehavior,
     );