1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/rendering.dart'; |
6 | |
7 | import 'framework.dart'; |
8 | import 'scroll_delegate.dart'; |
9 | import 'sliver.dart'; |
10 | |
11 | /// A sliver that places its box children in a linear array and constrains them |
12 | /// to have the corresponding extent returned by [itemExtentBuilder]. |
13 | /// |
14 | /// _To learn more about slivers, see [CustomScrollView.slivers]._ |
15 | /// |
16 | /// [SliverVariedExtentList] arranges its children in a line along |
17 | /// the main axis starting at offset zero and without gaps. Each child is |
18 | /// constrained to the corresponding extent along the main axis |
19 | /// and the [SliverConstraints.crossAxisExtent] along the cross axis. |
20 | /// |
21 | /// [SliverVariedExtentList] is more efficient than [SliverList] because |
22 | /// [SliverVariedExtentList] does not need to lay out its children to obtain |
23 | /// their extent along the main axis. It's a little more flexible than |
24 | /// [SliverFixedExtentList] because this allow the children to have different extents. |
25 | /// |
26 | /// See also: |
27 | /// |
28 | /// * [SliverFixedExtentList], whose children are forced to a given pixel |
29 | /// extent. |
30 | /// * [SliverList], which does not require its children to have the same |
31 | /// extent in the main axis. |
32 | /// * [SliverFillViewport], which sizes its children based on the |
33 | /// size of the viewport, regardless of what else is in the scroll view. |
34 | class SliverVariedExtentList extends SliverMultiBoxAdaptorWidget { |
35 | /// Creates a sliver that places box children with the same main axis extent |
36 | /// in a linear array. |
37 | const SliverVariedExtentList({ |
38 | super.key, |
39 | required super.delegate, |
40 | required this.itemExtentBuilder, |
41 | }); |
42 | |
43 | /// A sliver that places multiple box children in a linear array along the main |
44 | /// axis. |
45 | /// |
46 | /// [SliverVariedExtentList] places its children in a linear array along the main |
47 | /// axis starting at offset zero and without gaps. Each child is forced to have |
48 | /// the returned extent of [itemExtentBuilder] in the main axis and the |
49 | /// [SliverConstraints.crossAxisExtent] in the cross axis. |
50 | /// |
51 | /// This constructor is appropriate for sliver lists with a large (or |
52 | /// infinite) number of children whose extent is already determined. |
53 | /// |
54 | /// Providing a non-null `itemCount` improves the ability of the [SliverGrid] |
55 | /// to estimate the maximum scroll extent. |
56 | SliverVariedExtentList.builder({ |
57 | super.key, |
58 | required NullableIndexedWidgetBuilder itemBuilder, |
59 | required this.itemExtentBuilder, |
60 | ChildIndexGetter? findChildIndexCallback, |
61 | int? itemCount, |
62 | bool addAutomaticKeepAlives = true, |
63 | bool addRepaintBoundaries = true, |
64 | bool addSemanticIndexes = true, |
65 | }) : super(delegate: SliverChildBuilderDelegate( |
66 | itemBuilder, |
67 | findChildIndexCallback: findChildIndexCallback, |
68 | childCount: itemCount, |
69 | addAutomaticKeepAlives: addAutomaticKeepAlives, |
70 | addRepaintBoundaries: addRepaintBoundaries, |
71 | addSemanticIndexes: addSemanticIndexes, |
72 | )); |
73 | |
74 | /// A sliver that places multiple box children in a linear array along the main |
75 | /// axis. |
76 | /// |
77 | /// [SliverVariedExtentList] places its children in a linear array along the main |
78 | /// axis starting at offset zero and without gaps. Each child is forced to have |
79 | /// the returned extent of [itemExtentBuilder] in the main axis and the |
80 | /// [SliverConstraints.crossAxisExtent] in the cross axis. |
81 | /// |
82 | /// This constructor uses a list of [Widget]s to build the sliver. |
83 | SliverVariedExtentList.list({ |
84 | super.key, |
85 | required List<Widget> children, |
86 | required this.itemExtentBuilder, |
87 | bool addAutomaticKeepAlives = true, |
88 | bool addRepaintBoundaries = true, |
89 | bool addSemanticIndexes = true, |
90 | }) : super(delegate: SliverChildListDelegate( |
91 | children, |
92 | addAutomaticKeepAlives: addAutomaticKeepAlives, |
93 | addRepaintBoundaries: addRepaintBoundaries, |
94 | addSemanticIndexes: addSemanticIndexes, |
95 | )); |
96 | |
97 | /// The children extent builder. |
98 | final ItemExtentBuilder itemExtentBuilder; |
99 | |
100 | @override |
101 | RenderSliverVariedExtentList createRenderObject(BuildContext context) { |
102 | final SliverMultiBoxAdaptorElement element = context as SliverMultiBoxAdaptorElement; |
103 | return RenderSliverVariedExtentList(childManager: element, itemExtentBuilder: itemExtentBuilder); |
104 | } |
105 | |
106 | @override |
107 | void updateRenderObject(BuildContext context, RenderSliverVariedExtentList renderObject) { |
108 | renderObject.itemExtentBuilder = itemExtentBuilder; |
109 | } |
110 | } |
111 | |
112 | /// A sliver that places multiple box children with the corresponding main axis extent in |
113 | /// a linear array. |
114 | class RenderSliverVariedExtentList extends RenderSliverFixedExtentBoxAdaptor { |
115 | /// Creates a sliver that contains multiple box children that have a explicit |
116 | /// extent in the main axis. |
117 | RenderSliverVariedExtentList({ |
118 | required super.childManager, |
119 | required ItemExtentBuilder itemExtentBuilder, |
120 | }) : _itemExtentBuilder = itemExtentBuilder; |
121 | |
122 | @override |
123 | ItemExtentBuilder get itemExtentBuilder => _itemExtentBuilder; |
124 | ItemExtentBuilder _itemExtentBuilder; |
125 | set itemExtentBuilder(ItemExtentBuilder value) { |
126 | if (_itemExtentBuilder == value) { |
127 | return; |
128 | } |
129 | _itemExtentBuilder = value; |
130 | markNeedsLayout(); |
131 | } |
132 | |
133 | @override |
134 | double? get itemExtent => null; |
135 | } |
136 | |