diff --git a/packages/flutter/lib/src/widgets/scrollbar.dart b/packages/flutter/lib/src/widgets/scrollbar.dart index 9ed1b69d9c..413a4a1f3c 100644 --- a/packages/flutter/lib/src/widgets/scrollbar.dart +++ b/packages/flutter/lib/src/widgets/scrollbar.dart @@ -1447,6 +1447,9 @@ class RawScrollbarState extends State with TickerProv } bool _debugCheckHasValidScrollPosition() { + if (!mounted) { + return true; + } final ScrollController? scrollController = widget.controller ?? PrimaryScrollController.of(context); final bool tryPrimary = widget.controller == null; final String controllerForError = tryPrimary diff --git a/packages/flutter/test/widgets/scrollbar_test.dart b/packages/flutter/test/widgets/scrollbar_test.dart index d0ce262492..3b551a9d1b 100644 --- a/packages/flutter/test/widgets/scrollbar_test.dart +++ b/packages/flutter/test/widgets/scrollbar_test.dart @@ -2444,4 +2444,42 @@ void main() { } expect(() => tester.pumpWidget(buildApp()), throwsAssertionError); }); + + testWidgets('Skip the ScrollPosition check if the bar was unmounted', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/103939 + final ScrollController scrollController = ScrollController(); + Widget buildApp(bool buildBar) { + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData( + invertColors: buildBar, // Trigger a post frame check before unmount. + ), + child: PrimaryScrollController( + controller: scrollController, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + Widget content = const SingleChildScrollView( + child: SizedBox(width: 4000.0, height: 4000.0), + ); + if (buildBar) { + content = RawScrollbar( + thumbVisibility: true, + child: content, + ); + } + return content; + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildApp(true)); + + await tester.pumpWidget(buildApp(false)); + + // Go without throw. + }); }