@@ -731,6 +731,66 @@ void main() {
731
731
);
732
732
});
733
733
734
+ testWidgets ('Ensure KeepAlive widget is not held onto when it no longer should be kept alive offscreen' , (WidgetTester tester) async {
735
+ // Regression test for https://github.com/flutter/flutter/issues/138977
736
+ final UniqueKey checkBoxKey = UniqueKey ();
737
+ final Widget originCell = KeepAliveOnlyWhenHovered (
738
+ key: checkBoxKey,
739
+ child: const SizedBox .square (dimension: 200 ),
740
+ );
741
+ const Widget otherCell = SizedBox .square (dimension: 200 , child: Placeholder ());
742
+ final ScrollController verticalController = ScrollController ();
743
+ addTearDown (verticalController.dispose);
744
+ final TwoDimensionalChildListDelegate listDelegate = TwoDimensionalChildListDelegate (
745
+ children: < List <Widget >> [
746
+ < Widget > [originCell, otherCell, otherCell, otherCell, otherCell],
747
+ < Widget > [otherCell, otherCell, otherCell, otherCell, otherCell],
748
+ < Widget > [otherCell, otherCell, otherCell, otherCell, otherCell],
749
+ < Widget > [otherCell, otherCell, otherCell, otherCell, otherCell],
750
+ < Widget > [otherCell, otherCell, otherCell, otherCell, otherCell],
751
+ ],
752
+ );
753
+ addTearDown (listDelegate.dispose);
754
+
755
+ await tester.pumpWidget (simpleListTest (
756
+ delegate: listDelegate,
757
+ verticalDetails: ScrollableDetails .vertical (controller: verticalController),
758
+ ));
759
+ await tester.pumpAndSettle ();
760
+ expect (find.byKey (checkBoxKey), findsOneWidget);
761
+
762
+ // Scroll away, should not be kept alive (disposed).
763
+ verticalController.jumpTo (verticalController.position.maxScrollExtent);
764
+ await tester.pump ();
765
+ expect (find.byKey (checkBoxKey), findsNothing);
766
+
767
+ // Bring back into view
768
+ verticalController.jumpTo (0.0 );
769
+ await tester.pump ();
770
+ expect (find.byKey (checkBoxKey), findsOneWidget);
771
+
772
+ // Hover over widget to make it keep alive.
773
+ final TestGesture gesture = await tester.createGesture (
774
+ kind: PointerDeviceKind .mouse,
775
+ );
776
+ await gesture.addPointer (location: Offset .zero);
777
+ addTearDown (gesture.removePointer);
778
+ await tester.pump ();
779
+ await gesture.moveTo (tester.getCenter (find.byKey (checkBoxKey)));
780
+ await tester.pump ();
781
+
782
+ // Scroll away, should be kept alive still.
783
+ verticalController.jumpTo (verticalController.position.maxScrollExtent);
784
+ await tester.pump ();
785
+ expect (find.byKey (checkBoxKey), findsOneWidget);
786
+
787
+ // Move the pointer outside the widget bounds to trigger exit event
788
+ // and remove it from keep alive bucket.
789
+ await gesture.moveTo (const Offset (300 , 300 ));
790
+ await tester.pump ();
791
+ expect (find.byKey (checkBoxKey), findsNothing);
792
+ });
793
+
734
794
testWidgets ('list delegate will not add automatic keep alives' , (WidgetTester tester) async {
735
795
final UniqueKey checkBoxKey = UniqueKey ();
736
796
final Widget originCell = SizedBox .square (
0 commit comments