Revert "Fix 25807: implement move for sliver multibox widget (#29188)" (#31497)
This reverts commit 77ab0b83214792e8e6117295982c9397e03193a2.
diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart
index 6045721..cf7c6d0 100644
--- a/packages/flutter/lib/src/material/tabs.dart
+++ b/packages/flutter/lib/src/material/tabs.dart
@@ -1116,7 +1116,6 @@
TabController _controller;
PageController _pageController;
List<Widget> _children;
- List<Widget> _childrenWithKey;
int _currentIndex;
int _warpUnderwayCount = 0;
@@ -1158,7 +1157,7 @@
@override
void initState() {
super.initState();
- _updateChildren();
+ _children = widget.children;
}
@override
@@ -1175,7 +1174,7 @@
if (widget.controller != oldWidget.controller)
_updateTabController();
if (widget.children != oldWidget.children && _warpUnderwayCount == 0)
- _updateChildren();
+ _children = widget.children;
}
@override
@@ -1186,11 +1185,6 @@
super.dispose();
}
- void _updateChildren() {
- _children = widget.children;
- _childrenWithKey = KeyedSubtree.ensureUniqueKeysForList(widget.children);
- }
-
void _handleTabControllerAnimationTick() {
if (_warpUnderwayCount > 0 || !_controller.indexIsChanging)
return; // This widget is driving the controller's animation.
@@ -1213,30 +1207,28 @@
return _pageController.animateToPage(_currentIndex, duration: kTabScrollDuration, curve: Curves.ease);
assert((_currentIndex - previousIndex).abs() > 1);
- final int initialPage = _currentIndex > previousIndex
- ? _currentIndex - 1
- : _currentIndex + 1;
- final List<Widget> originalChildren = _childrenWithKey;
+ int initialPage;
setState(() {
_warpUnderwayCount += 1;
-
- _childrenWithKey = List<Widget>.from(_childrenWithKey, growable: false);
- final Widget temp = _childrenWithKey[initialPage];
- _childrenWithKey[initialPage] = _childrenWithKey[previousIndex];
- _childrenWithKey[previousIndex] = temp;
+ _children = List<Widget>.from(widget.children, growable: false);
+ if (_currentIndex > previousIndex) {
+ _children[_currentIndex - 1] = _children[previousIndex];
+ initialPage = _currentIndex - 1;
+ } else {
+ _children[_currentIndex + 1] = _children[previousIndex];
+ initialPage = _currentIndex + 1;
+ }
});
+
_pageController.jumpToPage(initialPage);
await _pageController.animateToPage(_currentIndex, duration: kTabScrollDuration, curve: Curves.ease);
if (!mounted)
return Future<void>.value();
+
setState(() {
_warpUnderwayCount -= 1;
- if (widget.children != _children) {
- _updateChildren();
- } else {
- _childrenWithKey = originalChildren;
- }
+ _children = widget.children;
});
}
@@ -1272,7 +1264,7 @@
dragStartBehavior: widget.dragStartBehavior,
controller: _pageController,
physics: widget.physics == null ? _kTabBarViewPhysics : _kTabBarViewPhysics.applyTo(widget.physics),
- children: _childrenWithKey,
+ children: _children,
),
);
}
diff --git a/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart b/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart
index 0280a6e..e950078 100644
--- a/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart
+++ b/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart
@@ -85,8 +85,7 @@
/// list).
int get childCount;
- /// Called during [RenderSliverMultiBoxAdaptor.adoptChild] or
- /// [RenderSliverMultiBoxAdaptor.move].
+ /// Called during [RenderSliverMultiBoxAdaptor.adoptChild].
///
/// Subclasses must ensure that the [SliverMultiBoxAdaptorParentData.index]
/// field of the child's [RenderObject.parentData] accurately reflects the
@@ -194,12 +193,7 @@
RenderSliverMultiBoxAdaptor({
@required RenderSliverBoxChildManager childManager,
}) : assert(childManager != null),
- _childManager = childManager {
- assert(() {
- _debugDanglingKeepAlives = <RenderBox>[];
- return true;
- }());
- }
+ _childManager = childManager;
@override
void setupParentData(RenderObject child) {
@@ -220,27 +214,6 @@
/// The nodes being kept alive despite not being visible.
final Map<int, RenderBox> _keepAliveBucket = <int, RenderBox>{};
- List<RenderBox> _debugDanglingKeepAlives;
-
- /// Indicates whether integrity check is enabled.
- ///
- /// Setting this property to true will immediately perform an integrity check.
- ///
- /// The integrity check consists of:
- ///
- /// 1. Verify that the children index in childList is in ascending order.
- /// 2. Verify that there is no dangling keepalive child as the result of [move].
- bool get debugChildIntegrityEnabled => _debugChildIntegrityEnabled;
- bool _debugChildIntegrityEnabled = true;
- set debugChildIntegrityEnabled(bool enabled) {
- assert(enabled != null);
- assert(() {
- _debugChildIntegrityEnabled = enabled;
- return _debugVerifyChildOrder() &&
- (!_debugChildIntegrityEnabled || _debugDanglingKeepAlives.isEmpty);
- }());
- }
-
@override
void adoptChild(RenderObject child) {
super.adoptChild(child);
@@ -251,70 +224,21 @@
bool _debugAssertChildListLocked() => childManager.debugAssertChildListLocked();
- /// Verify that the child list index is in strictly increasing order.
- ///
- /// This has no effect in release builds.
- bool _debugVerifyChildOrder(){
- if (_debugChildIntegrityEnabled) {
- RenderBox child = firstChild;
- int index;
- while (child != null) {
- index = indexOf(child);
- child = childAfter(child);
- assert(child == null || indexOf(child) > index);
- }
- }
- return true;
- }
-
@override
void insert(RenderBox child, { RenderBox after }) {
assert(!_keepAliveBucket.containsValue(child));
super.insert(child, after: after);
assert(firstChild != null);
- assert(_debugVerifyChildOrder());
- }
-
- @override
- void move(RenderBox child, { RenderBox after }) {
- // There are two scenarios:
- //
- // 1. The child is not keptAlive.
- // The child is in the childList maintained by ContainerRenderObjectMixin.
- // We can call super.move and update parentData with the new slot.
- //
- // 2. The child is keptAlive.
- // In this case, the child is no longer in the childList but might be stored in
- // [_keepAliveBucket]. We need to update the location of the child in the bucket.
- final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
- if (!childParentData.keptAlive) {
- super.move(child, after: after);
- childManager.didAdoptChild(child); // updates the slot in the parentData
- // Its slot may change even if super.move does not change the position.
- // In this case, we still want to mark as needs layout.
- markNeedsLayout();
- } else {
- // If the child in the bucket is not current child, that means someone has
- // already moved and replaced current child, and we cannot remove this child.
- if (_keepAliveBucket[childParentData.index] == child) {
- _keepAliveBucket.remove(childParentData.index);
+ assert(() {
+ int index = indexOf(firstChild);
+ RenderBox child = childAfter(firstChild);
+ while (child != null) {
+ assert(indexOf(child) > index);
+ index = indexOf(child);
+ child = childAfter(child);
}
- assert(() {
- _debugDanglingKeepAlives.remove(child);
- return true;
- }());
- // Update the slot and reinsert back to _keepAliveBucket in the new slot.
- childManager.didAdoptChild(child);
- // If there is an existing child in the new slot, that mean that child will
- // be moved to other index. In other cases, the existing child should have been
- // removed by updateChild. Thus, it is ok to overwrite it.
- assert(() {
- if (_keepAliveBucket.containsKey(childParentData.index))
- _debugDanglingKeepAlives.add(_keepAliveBucket[childParentData.index]);
- return true;
- }());
- _keepAliveBucket[childParentData.index] = child;
- }
+ return true;
+ }());
}
@override
@@ -325,10 +249,6 @@
return;
}
assert(_keepAliveBucket[childParentData.index] == child);
- assert(() {
- _debugDanglingKeepAlives.remove(child);
- return true;
- }());
_keepAliveBucket.remove(childParentData.index);
dropChild(child);
}
diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart
index 7e59cac..31d34f2 100644
--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -149,13 +149,6 @@
assert(() {
assert(parent != null);
if (_debugReservations.containsKey(this) && _debugReservations[this] != parent) {
- // Reserving a new parent while the old parent is not attached is ok.
- // This can happen when a renderObject detaches and re-attaches to rendering
- // tree multiple times.
- if (_debugReservations[this].renderObject?.attached == false) {
- _debugReservations[this] = parent;
- return true;
- }
// It's possible for an element to get built multiple times in one
// frame, in which case it'll reserve the same child's key multiple
// times. We catch multiple children of one widget having the same key
diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart
index 0ad64e2..d551a09 100644
--- a/packages/flutter/lib/src/widgets/sliver.dart
+++ b/packages/flutter/lib/src/widgets/sliver.dart
@@ -174,13 +174,6 @@
/// away.
bool shouldRebuild(covariant SliverChildDelegate oldDelegate);
- /// Find index of child element with associated key.
- ///
- /// This will be called during [performRebuild] in [SliverMultiBoxAdaptorElement]
- /// to check if a child has moved to a different position. It should return the
- /// index of the child element with associated key, null if not found.
- int findIndexByKey(Key key) => null;
-
@override
String toString() {
final List<String> description = <String>[];
@@ -202,12 +195,6 @@
}
}
-class _SaltedValueKey extends ValueKey<Key>{
- const _SaltedValueKey(Key key): assert(key != null), super(key);
-}
-
-typedef ChildIndexGetter = int Function(Key key);
-
/// A delegate that supplies children for slivers using a builder callback.
///
/// Many slivers lazily construct their box children to avoid creating more
@@ -319,14 +306,8 @@
/// The [builder], [addAutomaticKeepAlives], [addRepaintBoundaries],
/// [addSemanticIndexes], and [semanticIndexCallback] arguments must not be
/// null.
- ///
- /// If the order in which [builder] returns children ever changes, consider
- /// providing a [findChildIndex]. This allows the delegate to find the new index
- /// for a child that was previously located at a different index to attach the
- /// existing state to the [Widget] at its new location.
const SliverChildBuilderDelegate(
this.builder, {
- this.findChildIndexCallback,
this.childCount,
this.addAutomaticKeepAlives = true,
this.addRepaintBoundaries = true,
@@ -407,31 +388,6 @@
/// Defaults to providing an index for each widget.
final SemanticIndexCallback semanticIndexCallback;
- /// Called to find the new index of a child based on its key in case of reordering.
- ///
- /// If not provided, a child widget may not map to its existing [RenderObject]
- /// when the order in which children are returned from [builder] changes.
- /// This may result in state-loss.
- ///
- /// This callback should take an input [Key], and It should return the
- /// index of the child element with associated key, null if not found.
- final ChildIndexGetter findChildIndexCallback;
-
- @override
- int findIndexByKey(Key key) {
- if (findChildIndexCallback == null)
- return null;
- assert(key != null);
- Key childKey;
- if (key is _SaltedValueKey) {
- final _SaltedValueKey saltedValueKey = key;
- childKey = saltedValueKey.value;
- } else {
- childKey = key;
- }
- return findChildIndexCallback(childKey);
- }
-
@override
Widget build(BuildContext context, int index) {
assert(builder != null);
@@ -445,9 +401,8 @@
}
if (child == null)
return null;
- final Key key = child.key != null ? _SaltedValueKey(child.key) : null;
if (addRepaintBoundaries)
- child = RepaintBoundary(child: child);
+ child = RepaintBoundary.wrap(child, index);
if (addSemanticIndexes) {
final int semanticIndex = semanticIndexCallback(child, index);
if (semanticIndex != null)
@@ -455,7 +410,7 @@
}
if (addAutomaticKeepAlives)
child = AutomaticKeepAlive(child: child);
- return KeyedSubtree(child: child, key: key);
+ return child;
}
@override
@@ -523,10 +478,7 @@
/// The [children], [addAutomaticKeepAlives], [addRepaintBoundaries],
/// [addSemanticIndexes], and [semanticIndexCallback] arguments must not be
/// null.
- ///
- /// If the order of children` never changes, consider using the constant
- /// [SliverChildListDelegate.fixed] constructor.
- SliverChildListDelegate(
+ const SliverChildListDelegate(
this.children, {
this.addAutomaticKeepAlives = true,
this.addRepaintBoundaries = true,
@@ -537,31 +489,7 @@
assert(addAutomaticKeepAlives != null),
assert(addRepaintBoundaries != null),
assert(addSemanticIndexes != null),
- assert(semanticIndexCallback != null),
- _keyToIndex = <Key, int>{null: 0};
-
- /// Creates a constant version of the delegate that supplies children for
- /// slivers using the given list.
- ///
- /// If the order of the children will change, consider using the regular
- /// [SliverChildListDelegate] constructor.
- ///
- /// The [children], [addAutomaticKeepAlives], [addRepaintBoundaries],
- /// [addSemanticIndexes], and [semanticIndexCallback] arguments must not be
- /// null.
- const SliverChildListDelegate.fixed(
- this.children, {
- this.addAutomaticKeepAlives = true,
- this.addRepaintBoundaries = true,
- this.addSemanticIndexes = true,
- this.semanticIndexCallback = _kDefaultSemanticIndexCallback,
- this.semanticIndexOffset = 0,
- }) : assert(children != null),
- assert(addAutomaticKeepAlives != null),
- assert(addRepaintBoundaries != null),
- assert(addSemanticIndexes != null),
- assert(semanticIndexCallback != null),
- _keyToIndex = null;
+ assert(semanticIndexCallback != null);
/// Whether to wrap each child in an [AutomaticKeepAlive].
///
@@ -616,63 +544,15 @@
/// The widgets to display.
final List<Widget> children;
- /// A map to cache key to index lookup for children.
- ///
- /// _keyToIndex[null] is used as current index during the lazy loading process
- /// in [_findChildIndex]. _keyToIndex should never be used for looking up null key.
- final Map<Key, int> _keyToIndex;
-
- bool get _isConstantInstance => _keyToIndex == null;
-
- int _findChildIndex(Key key) {
- if (_isConstantInstance) {
- return null;
- }
- // Lazily fill the [_keyToIndex].
- if (!_keyToIndex.containsKey(key)) {
- int index = _keyToIndex[null];
- while (index < children.length) {
- final Widget child = children[index];
- if (child.key != null) {
- _keyToIndex[child.key] = index;
- }
- if (child.key == key) {
- // Record current index for next function call.
- _keyToIndex[null] = index + 1;
- return index;
- }
- index += 1;
- }
- _keyToIndex[null] = index;
- } else {
- return _keyToIndex[key];
- }
- return null;
- }
-
- @override
- int findIndexByKey(Key key) {
- assert(key != null);
- Key childKey;
- if (key is _SaltedValueKey) {
- final _SaltedValueKey saltedValueKey = key;
- childKey = saltedValueKey.value;
- } else {
- childKey = key;
- }
- return _findChildIndex(childKey);
- }
-
@override
Widget build(BuildContext context, int index) {
assert(children != null);
if (index < 0 || index >= children.length)
return null;
Widget child = children[index];
- final Key key = child.key != null? _SaltedValueKey(child.key) : null;
assert(child != null);
if (addRepaintBoundaries)
- child = RepaintBoundary(child: child);
+ child = RepaintBoundary.wrap(child, index);
if (addSemanticIndexes) {
final int semanticIndex = semanticIndexCallback(child, index);
if (semanticIndex != null)
@@ -680,7 +560,7 @@
}
if (addAutomaticKeepAlives)
child = AutomaticKeepAlive(child: child);
- return KeyedSubtree(child: child, key: key);
+ return child;
}
@override
@@ -1099,15 +979,9 @@
_currentBeforeChild = null;
assert(_currentlyUpdatingChildIndex == null);
try {
- final SplayTreeMap<int, Element> newChildren = SplayTreeMap<int, Element>();
-
void processElement(int index) {
_currentlyUpdatingChildIndex = index;
- if (_childElements[index] != null && _childElements[index] != newChildren[index]) {
- // This index has an old child that isn't used anywhere and should be deactivated.
- _childElements[index] = updateChild(_childElements[index], null, index);
- }
- final Element newChild = updateChild(newChildren[index], _build(index), index);
+ final Element newChild = updateChild(_childElements[index], _build(index), index);
if (newChild != null) {
_childElements[index] = newChild;
final SliverMultiBoxAdaptorParentData parentData = newChild.renderObject.parentData;
@@ -1117,32 +991,14 @@
_childElements.remove(index);
}
}
-
- for (int index in _childElements.keys.toList()) {
- final Key key = _childElements[index].widget.key;
- final int newIndex = key == null ? null : widget.delegate.findIndexByKey(key);
- if (newIndex != null && newIndex != index) {
- newChildren[newIndex] = _childElements[index];
- // We need to make sure the original index gets processed.
- newChildren.putIfAbsent(index, () => null);
- // We do not want the remapped child to get deactivated during processElement.
- _childElements.remove(index);
- } else {
- newChildren.putIfAbsent(index, () => _childElements[index]);
- }
- }
-
- renderObject.debugChildIntegrityEnabled = false; // Moving children will temporary violate the integrity.
- newChildren.keys.forEach(processElement);
+ // processElement may modify the Map - need to do a .toList() here.
+ _childElements.keys.toList().forEach(processElement);
if (_didUnderflow) {
final int lastKey = _childElements.lastKey() ?? -1;
- final int rightBoundary = lastKey + 1;
- newChildren[rightBoundary] = _childElements[rightBoundary];
- processElement(rightBoundary);
+ processElement(lastKey + 1);
}
} finally {
_currentlyUpdatingChildIndex = null;
- renderObject.debugChildIntegrityEnabled = true;
}
}
@@ -1182,6 +1038,7 @@
if (oldParentData != newParentData && oldParentData != null && newParentData != null) {
newParentData.layoutOffset = oldParentData.layoutOffset;
}
+
return newChild;
}
@@ -1306,9 +1163,9 @@
@override
void moveChildRenderObject(covariant RenderObject child, int slot) {
- assert(slot != null);
- assert(_currentlyUpdatingChildIndex == slot);
- renderObject.move(child, after: _currentBeforeChild);
+ // TODO(ianh): At some point we should be better about noticing when a
+ // particular LocalKey changes slot, and handle moving the nodes around.
+ assert(false);
}
@override
diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart
index 5a0fcd5..2ecefce 100644
--- a/packages/flutter/test/material/tabs_test.dart
+++ b/packages/flutter/test/material/tabs_test.dart
@@ -49,7 +49,6 @@
}
class AlwaysKeepAliveWidget extends StatefulWidget {
- const AlwaysKeepAliveWidget({ Key key}) : super(key: key);
static String text = 'AlwaysKeepAlive';
@override
AlwaysKeepAliveState createState() => AlwaysKeepAliveState();
@@ -1988,56 +1987,6 @@
});
- testWidgets('Skipping tabs with global key does not crash', (WidgetTester tester) async {
- // Regression test for https://github.com/flutter/flutter/issues/24660
- final List<String> tabs = <String>[
- 'Tab1',
- 'Tab2',
- 'Tab3',
- 'Tab4',
- ];
- final TabController controller = TabController(
- vsync: const TestVSync(),
- length: tabs.length,
- );
- await tester.pumpWidget(
- MaterialApp(
- home: Align(
- alignment: Alignment.topLeft,
- child: SizedBox(
- width: 300.0,
- height: 200.0,
- child: Scaffold(
- appBar: AppBar(
- title: const Text('tabs'),
- bottom: TabBar(
- controller: controller,
- tabs: tabs.map<Widget>((String tab) => Tab(text: tab)).toList(),
- ),
- ),
- body: TabBarView(
- controller: controller,
- children: <Widget>[
- Text('1', key: GlobalKey()),
- Text('2', key: GlobalKey()),
- Text('3', key: GlobalKey()),
- Text('4', key: GlobalKey()),
- ],
- ),
- ),
- ),
- ),
- ),
- );
- expect(find.text('1'), findsOneWidget);
- expect(find.text('4'), findsNothing);
- await tester.tap(find.text('Tab4'));
- await tester.pumpAndSettle();
- expect(controller.index, 3);
- expect(find.text('4'), findsOneWidget);
- expect(find.text('1'), findsNothing);
- });
-
testWidgets('Skipping tabs with a KeepAlive child works', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/11895
final List<String> tabs = <String>[
@@ -2069,7 +2018,7 @@
body: TabBarView(
controller: controller,
children: <Widget>[
- AlwaysKeepAliveWidget(key: UniqueKey()),
+ AlwaysKeepAliveWidget(),
const Text('2'),
const Text('3'),
const Text('4'),
diff --git a/packages/flutter/test/widgets/box_sliver_mismatch_test.dart b/packages/flutter/test/widgets/box_sliver_mismatch_test.dart
index 6828d01..fe93c90 100644
--- a/packages/flutter/test/widgets/box_sliver_mismatch_test.dart
+++ b/packages/flutter/test/widgets/box_sliver_mismatch_test.dart
@@ -9,10 +9,10 @@
void main() {
testWidgets('Sliver in a box', (WidgetTester tester) async {
await tester.pumpWidget(
- DecoratedBox(
- decoration: const BoxDecoration(),
+ const DecoratedBox(
+ decoration: BoxDecoration(),
child: SliverList(
- delegate: SliverChildListDelegate(const <Widget>[]),
+ delegate: SliverChildListDelegate(<Widget>[]),
),
),
);
@@ -21,9 +21,9 @@
await tester.pumpWidget(
Row(
- children: <Widget>[
+ children: const <Widget>[
SliverList(
- delegate: SliverChildListDelegate(const <Widget>[]),
+ delegate: SliverChildListDelegate(<Widget>[]),
),
],
),
diff --git a/packages/flutter/test/widgets/framework_test.dart b/packages/flutter/test/widgets/framework_test.dart
index 6a22359..69dddba 100644
--- a/packages/flutter/test/widgets/framework_test.dart
+++ b/packages/flutter/test/widgets/framework_test.dart
@@ -451,41 +451,6 @@
expect(count, 2);
});
- testWidgets('GlobalKey - dettach and re-attach child to different parents', (WidgetTester tester) async {
- await tester.pumpWidget(Directionality(
- textDirection: TextDirection.ltr,
- child: Center(
- child: Container(
- height: 100,
- child: CustomScrollView(
- controller: ScrollController(),
- slivers: <Widget>[
- SliverList(
- delegate: SliverChildListDelegate(<Widget>[
- Text('child', key: GlobalKey()),
- ]),
- )
- ],
- ),
- ),
- ),
- ));
- final SliverMultiBoxAdaptorElement element = tester.element(find.byType(SliverList));
- Element childElement;
- // Removing and recreating child with same Global Key should not trigger
- // duplicate key error.
- element.visitChildren((Element e) {
- childElement = e;
- });
- element.removeChild(childElement.renderObject);
- element.createChild(0, after: null);
- element.visitChildren((Element e) {
- childElement = e;
- });
- element.removeChild(childElement.renderObject);
- element.createChild(0, after: null);
- });
-
testWidgets('Defunct setState throws exception', (WidgetTester tester) async {
StateSetter setState;
diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart
index f6ac603..d0f2468 100644
--- a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart
+++ b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart
@@ -22,12 +22,12 @@
data: const MediaQueryData(),
child: CustomScrollView(
controller: controller,
- slivers: <Widget>[
- const SliverAppBar(floating: true, pinned: true, expandedHeight: 200.0, title: Text('A')),
- const SliverAppBar(primary: false, pinned: true, title: Text('B')),
+ slivers: const <Widget>[
+ SliverAppBar(floating: true, pinned: true, expandedHeight: 200.0, title: Text('A')),
+ SliverAppBar(primary: false, pinned: true, title: Text('B')),
SliverList(
delegate: SliverChildListDelegate(
- const <Widget>[
+ <Widget>[
Text('C'),
Text('D'),
SizedBox(height: 500.0),
diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_test.dart
index 548b43e..03603bd 100644
--- a/packages/flutter/test/widgets/slivers_appbar_floating_test.dart
+++ b/packages/flutter/test/widgets/slivers_appbar_floating_test.dart
@@ -203,9 +203,9 @@
physics: const BouncingScrollPhysics(),
slivers: <Widget>[
SliverPersistentHeader(delegate: TestDelegate(), floating: true),
- SliverList(
+ const SliverList(
delegate: SliverChildListDelegate(<Widget>[
- const SizedBox(
+ SizedBox(
height: 300.0,
child: Text('X'),
),
diff --git a/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart
index 1e85450..abb7e8c 100644
--- a/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart
+++ b/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart
@@ -258,9 +258,9 @@
physics: const BouncingScrollPhysics(),
slivers: <Widget>[
SliverPersistentHeader(delegate: TestDelegate(), pinned: true),
- SliverList(
+ const SliverList(
delegate: SliverChildListDelegate(<Widget>[
- const SizedBox(
+ SizedBox(
height: 300.0,
child: Text('X'),
),
diff --git a/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart b/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart
index bf3a6fd..e88a48c 100644
--- a/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart
+++ b/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart
@@ -82,40 +82,8 @@
physics: const BouncingScrollPhysics(),
slivers: <Widget>[
SliverPersistentHeader(delegate: TestDelegate()),
- SliverList(
- delegate: SliverChildListDelegate(<Widget>[
- const SizedBox(
- height: 300.0,
- child: Text('X'),
- ),
- ]),
- ),
- ],
- ),
- ),
- );
-
- expect(tester.getTopLeft(find.byType(Container)), Offset.zero);
- expect(tester.getTopLeft(find.text('X')), const Offset(0.0, 200.0));
-
- final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position;
- position.jumpTo(-50.0);
- await tester.pump();
-
- expect(tester.getTopLeft(find.byType(Container)), Offset.zero);
- expect(tester.getTopLeft(find.text('X')), const Offset(0.0, 250.0));
- });
-
- testWidgets('Sliver appbars const child delegate - scrolling - overscroll gap is below header', (WidgetTester tester) async {
- await tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: CustomScrollView(
- physics: const BouncingScrollPhysics(),
- slivers: <Widget>[
- SliverPersistentHeader(delegate: TestDelegate()),
const SliverList(
- delegate: SliverChildListDelegate.fixed(<Widget>[
+ delegate: SliverChildListDelegate(<Widget>[
SizedBox(
height: 300.0,
child: Text('X'),
diff --git a/packages/flutter/test/widgets/slivers_block_test.dart b/packages/flutter/test/widgets/slivers_block_test.dart
index 3869dc7..147b25b 100644
--- a/packages/flutter/test/widgets/slivers_block_test.dart
+++ b/packages/flutter/test/widgets/slivers_block_test.dart
@@ -14,31 +14,9 @@
textDirection: TextDirection.ltr,
child: Viewport(
offset: ViewportOffset.fixed(offset),
- slivers: <Widget>[
- SliverList(
- delegate: SliverChildListDelegate(const <Widget>[
- SizedBox(height: 400.0, child: Text('a')),
- SizedBox(height: 400.0, child: Text('b')),
- SizedBox(height: 400.0, child: Text('c')),
- SizedBox(height: 400.0, child: Text('d')),
- SizedBox(height: 400.0, child: Text('e')),
- ]),
- ),
- ],
- ),
- ),
- );
-}
-
-Future<void> testWithConstChildDelegate(WidgetTester tester, double offset) {
- return tester.pumpWidget(
- Directionality(
- textDirection: TextDirection.ltr,
- child: Viewport(
- offset: ViewportOffset.fixed(offset),
slivers: const <Widget>[
SliverList(
- delegate: SliverChildListDelegate.fixed(<Widget>[
+ delegate: SliverChildListDelegate(<Widget>[
SizedBox(height: 400.0, child: Text('a')),
SizedBox(height: 400.0, child: Text('b')),
SizedBox(height: 400.0, child: Text('c')),
@@ -98,39 +76,6 @@
], 'ab');
});
- testWidgets('Viewport+SliverBlock basic test with constant SliverChildListDelegate', (WidgetTester tester) async {
- await testWithConstChildDelegate(tester, 0.0);
- expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0)));
- verify(tester, <Offset>[
- const Offset(0.0, 0.0),
- const Offset(0.0, 400.0),
- ], 'ab');
-
- await testWithConstChildDelegate(tester, 200.0);
- verify(tester, <Offset>[
- const Offset(0.0, -200.0),
- const Offset(0.0, 200.0),
- ], 'ab');
-
- await testWithConstChildDelegate(tester, 600.0);
- verify(tester, <Offset>[
- const Offset(0.0, -200.0),
- const Offset(0.0, 200.0),
- ], 'bc');
-
- await testWithConstChildDelegate(tester, 900.0);
- verify(tester, <Offset>[
- const Offset(0.0, -100.0),
- const Offset(0.0, 300.0),
- ], 'cd');
-
- await testWithConstChildDelegate(tester, 200.0);
- verify(tester, <Offset>[
- const Offset(0.0, -200.0),
- const Offset(0.0, 200.0),
- ], 'ab');
- });
-
testWidgets('Viewport with GlobalKey reparenting', (WidgetTester tester) async {
final Key key1 = GlobalKey();
final ViewportOffset offset = ViewportOffset.zero();
@@ -205,9 +150,9 @@
textDirection: TextDirection.ltr,
child: Viewport(
offset: offset,
- slivers: <Widget>[
+ slivers: const <Widget>[
SliverList(
- delegate: SliverChildListDelegate(const <Widget>[
+ delegate: SliverChildListDelegate(<Widget>[
SizedBox(height: 251.0, child: Text('a')),
SizedBox(height: 252.0, child: Text('b')),
]),
@@ -316,9 +261,9 @@
textDirection: TextDirection.ltr,
child: Viewport(
offset: ViewportOffset.zero(),
- slivers: <Widget>[
+ slivers: const <Widget>[
SliverList(
- delegate: SliverChildListDelegate(const <Widget>[
+ delegate: SliverChildListDelegate(<Widget>[
SizedBox(height: 400.0, child: Text('a')),
]),
),
@@ -334,9 +279,9 @@
textDirection: TextDirection.ltr,
child: Viewport(
offset: ViewportOffset.fixed(100.0),
- slivers: <Widget>[
+ slivers: const <Widget>[
SliverList(
- delegate: SliverChildListDelegate(const <Widget>[
+ delegate: SliverChildListDelegate(<Widget>[
SizedBox(height: 400.0, child: Text('a')),
]),
),
@@ -352,9 +297,9 @@
textDirection: TextDirection.ltr,
child: Viewport(
offset: ViewportOffset.fixed(100.0),
- slivers: <Widget>[
+ slivers: const <Widget>[
SliverList(
- delegate: SliverChildListDelegate(const <Widget>[
+ delegate: SliverChildListDelegate(<Widget>[
SizedBox(height: 4000.0, child: Text('a')),
]),
),
@@ -370,9 +315,9 @@
textDirection: TextDirection.ltr,
child: Viewport(
offset: ViewportOffset.zero(),
- slivers: <Widget>[
+ slivers: const <Widget>[
SliverList(
- delegate: SliverChildListDelegate(const <Widget>[
+ delegate: SliverChildListDelegate(<Widget>[
SizedBox(height: 4000.0, child: Text('a')),
]),
),
diff --git a/packages/flutter/test/widgets/slivers_keepalive_test.dart b/packages/flutter/test/widgets/slivers_keepalive_test.dart
deleted file mode 100644
index 964098a..0000000
--- a/packages/flutter/test/widgets/slivers_keepalive_test.dart
+++ /dev/null
@@ -1,646 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter/widgets.dart';
-import 'package:flutter/rendering.dart';
-
-void main() {
- testWidgets('Sliver with keep alive without key - should dispose after reodering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', keepAlive: true),
- WidgetTest1(text: 'child 1', keepAlive: true),
- WidgetTest2(text: 'child 2', keepAlive: true),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsNothing);
-
- expect(state0.hasBeenDisposed, true);
- expect(state2.hasBeenDisposed, false);
- });
-
- testWidgets('Sliver without keep alive without key - should dispose after reodering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0'),
- WidgetTest1(text: 'child 1'),
- WidgetTest2(text: 'child 2'),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsNothing);
-
- expect(state0.hasBeenDisposed, true);
- expect(state2.hasBeenDisposed, false);
- });
-
- testWidgets('Sliver without keep alive with key - should dispose after reodering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: GlobalKey()),
- WidgetTest1(text: 'child 1', key: GlobalKey()),
- WidgetTest2(text: 'child 2', key: GlobalKey()),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsNothing);
-
- expect(state0.hasBeenDisposed, true);
- expect(state2.hasBeenDisposed, false);
- });
-
- testWidgets('Sliver with keep alive with key - should not dispose after reodering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: GlobalKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', key: GlobalKey(), keepAlive: true),
- WidgetTest2(text: 'child 2', key: GlobalKey(), keepAlive: true),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
- expect(state0.hasBeenDisposed, false);
- expect(state2.hasBeenDisposed, false);
- });
-
- testWidgets('Sliver with keep alive with Unique key - should not dispose after reodering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', key: UniqueKey(), keepAlive: true),
- WidgetTest2(text: 'child 2', key: UniqueKey(), keepAlive: true),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
- expect(state0.hasBeenDisposed, false);
- expect(state2.hasBeenDisposed, false);
- });
-
- testWidgets('Sliver with keep alive with Value key - should not dispose after reodering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: const ValueKey<int>(0), keepAlive: true),
- WidgetTest1(text: 'child 1', key: const ValueKey<int>(1), keepAlive: true),
- WidgetTest2(text: 'child 2', key: const ValueKey<int>(2), keepAlive: true),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
- expect(state0.hasBeenDisposed, false);
- expect(state2.hasBeenDisposed, false);
- });
-
- testWidgets('Sliver complex case 1', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: GlobalKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', key: GlobalKey(), keepAlive: true),
- WidgetTest2(text: 'child 2', keepAlive: true),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest1State state1 = tester.state(find.byType(WidgetTest1));
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 1, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsOneWidget);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- expect(state0.hasBeenDisposed, false);
- expect(state1.hasBeenDisposed, false);
- // Child 2 does not have a key.
- expect(state2.hasBeenDisposed, true);
- });
-
- testWidgets('Sliver complex case 2', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: GlobalKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', key: UniqueKey()),
- WidgetTest2(text: 'child 2', keepAlive: true),
- ];
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- final _WidgetTest1State state1 = tester.state(find.byType(WidgetTest1));
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 1, 2);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(SwitchingChildListTest(children: childList));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- expect(state0.hasBeenDisposed, false);
- expect(state1.hasBeenDisposed, true);
- expect(state2.hasBeenDisposed, true);
- });
-
- testWidgets('Sliver with SliverChildBuilderDelegate', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', key: GlobalKey()),
- WidgetTest2(text: 'child 2', keepAlive: true),
- ];
- await tester.pumpWidget(SwitchingChildBuilderTest(children: childList));
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(SwitchingChildBuilderTest(children: childList));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 2'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(SwitchingChildBuilderTest(children: childList));
- final _WidgetTest1State state1 = tester.state(find.byType(WidgetTest1));
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 1, 2);
- await tester.pumpWidget(SwitchingChildBuilderTest(children: childList));
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 0', skipOffstage: false), findsOneWidget);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(SwitchingChildBuilderTest(children: childList));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1', skipOffstage: false), findsNothing);
- expect(find.text('child 2', skipOffstage: false), findsNothing);
-
- expect(state0.hasBeenDisposed, false);
- expect(state1.hasBeenDisposed, true);
- expect(state2.hasBeenDisposed, true);
- });
-
- testWidgets('SliverFillViewport should not dispose widget with key during in screen reordering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', key: UniqueKey()),
- WidgetTest2(text: 'child 2', keepAlive: true),
- ];
- await tester.pumpWidget(
- SwitchingChildListTest(children: childList, viewportFraction: 0.1)
- );
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- final _WidgetTest1State state1 = tester.state(find.byType(WidgetTest1));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 2'), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(
- SwitchingChildListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(
- SwitchingChildListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 1, 2);
- await tester.pumpWidget(
- SwitchingChildListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(
- SwitchingChildListTest(children: childList, viewportFraction: 0.1)
- );
-
- expect(state0.hasBeenDisposed, false);
- expect(state1.hasBeenDisposed, false);
- expect(state2.hasBeenDisposed, true);
- });
-
- testWidgets('SliverList should not dispose widget with key during in screen reordering', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', keepAlive: true),
- WidgetTest2(text: 'child 2', key: UniqueKey()),
- ];
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- final _WidgetTest1State state1 = tester.state(find.byType(WidgetTest1));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 2'), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 1, 2);
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 1, 2);
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 0, 2);
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
-
- childList = createSwitchedChildList(childList, 0, 1);
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
- expect(state0.hasBeenDisposed, false);
- expect(state1.hasBeenDisposed, true);
- expect(state2.hasBeenDisposed, false);
- });
-
- testWidgets('SliverList remove child from child list', (WidgetTester tester) async {
- List<Widget> childList= <Widget>[
- WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true),
- WidgetTest1(text: 'child 1', keepAlive: true),
- WidgetTest2(text: 'child 2', key: UniqueKey()),
- ];
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
- final _WidgetTest0State state0 = tester.state(find.byType(WidgetTest0));
- final _WidgetTest1State state1 = tester.state(find.byType(WidgetTest1));
- final _WidgetTest2State state2 = tester.state(find.byType(WidgetTest2));
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 2'), findsOneWidget);
-
- childList = createSwitchedChildList(childList, 0, 1);
- childList.removeAt(2);
- await tester.pumpWidget(
- SwitchingSliverListTest(children: childList, viewportFraction: 0.1)
- );
- expect(find.text('child 0'), findsOneWidget);
- expect(find.text('child 1'), findsOneWidget);
- expect(find.text('child 2'), findsNothing);
- expect(state0.hasBeenDisposed, false);
- expect(state1.hasBeenDisposed, true);
- expect(state2.hasBeenDisposed, true);
- });
-}
-
-List<Widget> createSwitchedChildList(List<Widget> childList, int i, int j) {
- final Widget w = childList[i];
- childList[i] = childList[j];
- childList[j] = w;
- return List<Widget>.from(childList);
-}
-
-class SwitchingChildBuilderTest extends StatefulWidget {
- SwitchingChildBuilderTest({
- this.children,
- Key key
- }) : super(key: key);
-
- final List<Widget> children;
-
- @override
- _SwitchingChildBuilderTest createState() => _SwitchingChildBuilderTest();
-}
-
-class _SwitchingChildBuilderTest extends State<SwitchingChildBuilderTest> {
- List<Widget> children;
- Map<Key, int> _mapKeyToIndex;
-
- @override
- void initState() {
- super.initState();
- children = widget.children;
- _mapKeyToIndex = <Key, int>{};
- for (int index = 0; index < children.length; index += 1) {
- final Key key = children[index].key;
- if (key != null) {
- _mapKeyToIndex[key] = index;
- }
- }
- }
-
- @override
- void didUpdateWidget(SwitchingChildBuilderTest oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (oldWidget.children != widget.children) {
- children = widget.children;
- _mapKeyToIndex = <Key, int>{};
- for (int index = 0; index < children.length; index += 1) {
- final Key key = children[index].key;
- if (key != null) {
- _mapKeyToIndex[key] = index;
- }
- }
- }
- }
-
- @override
- Widget build(BuildContext context) {
- return Directionality(
- textDirection: TextDirection.ltr,
- child: Center(
- child: Container(
- height: 100,
- child: CustomScrollView(
- cacheExtent: 0,
- slivers: <Widget>[
- SliverFillViewport(
- delegate: SliverChildBuilderDelegate(
- (BuildContext context, int index) {
- return children[index];
- },
- childCount: children.length,
- findChildIndexCallback: (Key key) {
- return _mapKeyToIndex[key] == null ? -1 : _mapKeyToIndex[key];
- }
- ),
- )
- ],
- ),
- ),
- ),
- );
- }
-}
-
-class SwitchingChildListTest extends StatefulWidget {
- SwitchingChildListTest({
- this.children,
- this.viewportFraction = 1.0,
- Key key
- }) : super(key: key);
-
- final List<Widget> children;
- final double viewportFraction;
-
- @override
- _SwitchingChildListTest createState() => _SwitchingChildListTest();
-}
-
-class _SwitchingChildListTest extends State<SwitchingChildListTest> {
- @override
- Widget build(BuildContext context) {
- return Directionality(
- textDirection: TextDirection.ltr,
- child: Center(
- child: Container(
- height: 100,
- child: CustomScrollView(
- cacheExtent: 0,
- slivers: <Widget>[
- SliverFillViewport(
- viewportFraction: widget.viewportFraction,
- delegate: SliverChildListDelegate(widget.children),
- )
- ],
- ),
- ),
- ),
- );
- }
-}
-
-class SwitchingSliverListTest extends StatefulWidget {
- SwitchingSliverListTest({
- this.children,
- this.viewportFraction = 1.0,
- Key key
- }) : super(key: key);
-
- final List<Widget> children;
- final double viewportFraction;
-
- @override
- _SwitchingSliverListTest createState() => _SwitchingSliverListTest();
-}
-
-class _SwitchingSliverListTest extends State<SwitchingSliverListTest> {
- @override
- Widget build(BuildContext context) {
- return Directionality(
- textDirection: TextDirection.ltr,
- child: Center(
- child: Container(
- height: 100,
- child: CustomScrollView(
- cacheExtent: 0,
- slivers: <Widget>[
- SliverList(
- delegate: SliverChildListDelegate(widget.children),
- )
- ],
- ),
- ),
- ),
- );
- }
-}
-
-class WidgetTest0 extends StatefulWidget {
- WidgetTest0({
- this.text,
- this.keepAlive = false,
- Key key
- }) : super(key: key);
-
- final String text;
- final bool keepAlive;
-
- @override
- _WidgetTest0State createState() => _WidgetTest0State();
-}
-
-class _WidgetTest0State extends State<WidgetTest0> with AutomaticKeepAliveClientMixin{
- bool hasBeenDisposed = false;
-
- @override
- Widget build(BuildContext context) {
- super.build(context);
- return Text(widget.text);
- }
-
- @override
- void dispose() {
- hasBeenDisposed = true;
- super.dispose();
- }
-
- @override
- bool get wantKeepAlive => widget.keepAlive;
-}
-
-class WidgetTest1 extends StatefulWidget {
- WidgetTest1({
- this.text,
- this.keepAlive = false,
- Key key
- }) : super(key: key);
-
- final String text;
- final bool keepAlive;
-
- @override
- _WidgetTest1State createState() => _WidgetTest1State();
-}
-
-class _WidgetTest1State extends State<WidgetTest1> with AutomaticKeepAliveClientMixin{
- bool hasBeenDisposed = false;
-
- @override
- Widget build(BuildContext context) {
- super.build(context);
- return Text(widget.text);
- }
-
- @override
- void dispose() {
- hasBeenDisposed = true;
- super.dispose();
- }
-
- @override
- bool get wantKeepAlive => widget.keepAlive;
-}
-
-class WidgetTest2 extends StatefulWidget {
- WidgetTest2({
- this.text,
- this.keepAlive = false,
- Key key
- }) : super(key: key);
-
- final String text;
- final bool keepAlive;
-
- @override
- _WidgetTest2State createState() => _WidgetTest2State();
-}
-
-class _WidgetTest2State extends State<WidgetTest2> with AutomaticKeepAliveClientMixin{
- bool hasBeenDisposed = false;
-
- @override
- Widget build(BuildContext context) {
- super.build(context);
- return Text(widget.text);
- }
-
- @override
- void dispose() {
- hasBeenDisposed = true;
- super.dispose();
- }
-
- @override
- bool get wantKeepAlive => widget.keepAlive;
-}
diff --git a/packages/flutter/test/widgets/slivers_test.dart b/packages/flutter/test/widgets/slivers_test.dart
index ed5e213..91b8041 100644
--- a/packages/flutter/test/widgets/slivers_test.dart
+++ b/packages/flutter/test/widgets/slivers_test.dart
@@ -206,8 +206,7 @@
addRepaintBoundaries: false,
addSemanticIndexes: false,
);
- final KeyedSubtree wrapped = builderThrowsDelegate.build(null, 0);
- expect(wrapped.child, errorText);
+ expect(builderThrowsDelegate.build(null, 0), errorText);
expect(tester.takeException(), 'builder');
ErrorWidget.builder = oldBuilder;
});