Fix DraggableScrollableController.animateTo leaks Ticker (#102504)

This commit is contained in:
Bruno Leroux 2022-04-26 11:24:05 +02:00 committed by GitHub
parent 646b910c9c
commit bc7d3bbc65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 0 deletions

View file

@ -52,6 +52,7 @@ typedef ScrollableWidgetBuilder = Widget Function(
/// constraints provided to an attached sheet change.
class DraggableScrollableController extends ChangeNotifier {
_DraggableScrollableSheetScrollController? _attachedController;
final Set<AnimationController> _animationControllers = <AnimationController>{};
/// Get the current size (as a fraction of the parent height) of the attached sheet.
double get size {
@ -115,6 +116,7 @@ class DraggableScrollableController extends ChangeNotifier {
vsync: _attachedController!.position.context.vsync,
value: _attachedController!.extent.currentSize,
);
_animationControllers.add(animationController);
_attachedController!.position.goIdle();
// This disables any snapping until the next user interaction with the sheet.
_attachedController!.extent.hasDragged = false;
@ -175,6 +177,7 @@ class DraggableScrollableController extends ChangeNotifier {
assert(_attachedController == null, 'Draggable scrollable controller is already attached to a sheet.');
_attachedController = scrollController;
_attachedController!.extent._currentSize.addListener(notifyListeners);
_attachedController!.onPositionDetached = _disposeAnimationControllers;
}
void _onExtentReplaced(_DraggableSheetExtent previousExtent) {
@ -193,6 +196,13 @@ class DraggableScrollableController extends ChangeNotifier {
_attachedController?.extent._currentSize.removeListener(notifyListeners);
_attachedController = null;
}
void _disposeAnimationControllers() {
for (final AnimationController animationController in _animationControllers) {
animationController.dispose();
}
_animationControllers.clear();
}
}
/// A container for a [Scrollable] that responds to drag gestures by resizing
@ -724,6 +734,7 @@ class _DraggableScrollableSheetScrollController extends ScrollController {
}) : assert(extent != null);
_DraggableSheetExtent extent;
VoidCallback? onPositionDetached;
@override
_DraggableScrollableSheetScrollPosition createScrollPosition(
@ -764,6 +775,12 @@ class _DraggableScrollableSheetScrollController extends ScrollController {
}
extent.updateSize(extent.initialSize, position.context.notificationContext!);
}
@override
void detach(ScrollPosition position) {
onPositionDetached?.call();
super.detach(position);
}
}
/// A scroll position that manages scroll activities for

View file

@ -1209,4 +1209,19 @@ void main() {
expect(controller.isAttached, true);
expect(controller.size, isNotNull);
});
testWidgets('DraggableScrollableController.animateTo should not leak Ticker', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/102483
final DraggableScrollableController controller = DraggableScrollableController();
await tester.pumpWidget(_boilerplate(() {}, controller: controller));
controller.animateTo(0.0, curve: Curves.linear, duration: const Duration(milliseconds: 200));
await tester.pump();
// Dispose the DraggableScrollableSheet
await tester.pumpWidget(const SizedBox.shrink());
// Controller should be detached and no exception should be thrown
expect(controller.isAttached, false);
expect(tester.takeException(), isNull);
});
}