Skip to content

Commit 12e6ff2

Browse files
authored
DropdownRoutePage should dispose the created ScrollController. (#133941)
1 parent aca91df commit 12e6ff2

2 files changed

Lines changed: 44 additions & 21 deletions

File tree

packages/flutter/lib/src/material/dropdown.dart

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,11 @@ class _DropdownMenuItemButton<T> extends StatefulWidget {
102102
required this.constraints,
103103
required this.itemIndex,
104104
required this.enableFeedback,
105+
required this.scrollController,
105106
});
106107

107108
final _DropdownRoute<T> route;
109+
final ScrollController scrollController;
108110
final EdgeInsets? padding;
109111
final Rect buttonRect;
110112
final BoxConstraints constraints;
@@ -131,7 +133,7 @@ class _DropdownMenuItemButtonState<T> extends State<_DropdownMenuItemButton<T>>
131133
widget.constraints.maxHeight,
132134
widget.itemIndex,
133135
);
134-
widget.route.scrollController!.animateTo(
136+
widget.scrollController.animateTo(
135137
menuLimits.scrollOffset,
136138
curve: Curves.easeInOut,
137139
duration: const Duration(milliseconds: 100),
@@ -205,6 +207,7 @@ class _DropdownMenu<T> extends StatefulWidget {
205207
this.dropdownColor,
206208
required this.enableFeedback,
207209
this.borderRadius,
210+
required this.scrollController,
208211
});
209212

210213
final _DropdownRoute<T> route;
@@ -214,6 +217,7 @@ class _DropdownMenu<T> extends StatefulWidget {
214217
final Color? dropdownColor;
215218
final bool enableFeedback;
216219
final BorderRadius? borderRadius;
220+
final ScrollController scrollController;
217221

218222
@override
219223
_DropdownMenuState<T> createState() => _DropdownMenuState<T>();
@@ -264,6 +268,7 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
264268
constraints: widget.constraints,
265269
itemIndex: itemIndex,
266270
enableFeedback: widget.enableFeedback,
271+
scrollController: widget.scrollController,
267272
),
268273
];
269274

@@ -304,7 +309,7 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
304309
platform: Theme.of(context).platform,
305310
),
306311
child: PrimaryScrollController(
307-
controller: widget.route.scrollController!,
312+
controller: widget.scrollController,
308313
child: Scrollbar(
309314
thumbVisibility: true,
310315
child: ListView(
@@ -447,7 +452,6 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
447452
final BorderRadius? borderRadius;
448453

449454
final List<double> itemHeights;
450-
ScrollController? scrollController;
451455

452456
@override
453457
Duration get transitionDuration => _kDropdownMenuDuration;
@@ -572,7 +576,7 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
572576
}
573577
}
574578

575-
class _DropdownRoutePage<T> extends StatelessWidget {
579+
class _DropdownRoutePage<T> extends StatefulWidget {
576580
const _DropdownRoutePage({
577581
super.key,
578582
required this.route,
@@ -603,29 +607,41 @@ class _DropdownRoutePage<T> extends StatelessWidget {
603607
final BorderRadius? borderRadius;
604608

605609
@override
606-
Widget build(BuildContext context) {
607-
assert(debugCheckHasDirectionality(context));
610+
State<_DropdownRoutePage<T>> createState() => _DropdownRoutePageState<T>();
611+
}
612+
613+
class _DropdownRoutePageState<T> extends State<_DropdownRoutePage<T>> {
614+
late ScrollController _scrollSontroller;
615+
616+
@override
617+
void initState(){
618+
super.initState();
608619

609620
// Computing the initialScrollOffset now, before the items have been laid
610621
// out. This only works if the item heights are effectively fixed, i.e. either
611622
// DropdownButton.itemHeight is specified or DropdownButton.itemHeight is null
612623
// and all of the items' intrinsic heights are less than kMinInteractiveDimension.
613624
// Otherwise the initialScrollOffset is just a rough approximation based on
614625
// treating the items as if their heights were all equal to kMinInteractiveDimension.
615-
if (route.scrollController == null) {
616-
final _MenuLimits menuLimits = route.getMenuLimits(buttonRect, constraints.maxHeight, selectedIndex);
617-
route.scrollController = ScrollController(initialScrollOffset: menuLimits.scrollOffset);
618-
}
626+
final _MenuLimits menuLimits = widget.route.getMenuLimits(widget.buttonRect, widget.constraints.maxHeight, widget.selectedIndex);
627+
_scrollSontroller = ScrollController(initialScrollOffset: menuLimits.scrollOffset);
628+
}
629+
630+
631+
@override
632+
Widget build(BuildContext context) {
633+
assert(debugCheckHasDirectionality(context));
619634

620635
final TextDirection? textDirection = Directionality.maybeOf(context);
621636
final Widget menu = _DropdownMenu<T>(
622-
route: route,
623-
padding: padding.resolve(textDirection),
624-
buttonRect: buttonRect,
625-
constraints: constraints,
626-
dropdownColor: dropdownColor,
627-
enableFeedback: enableFeedback,
628-
borderRadius: borderRadius,
637+
route: widget.route,
638+
padding: widget.padding.resolve(textDirection),
639+
buttonRect: widget.buttonRect,
640+
constraints: widget.constraints,
641+
dropdownColor: widget.dropdownColor,
642+
enableFeedback: widget.enableFeedback,
643+
borderRadius: widget.borderRadius,
644+
scrollController: _scrollSontroller,
629645
);
630646

631647
return MediaQuery.removePadding(
@@ -638,16 +654,22 @@ class _DropdownRoutePage<T> extends StatelessWidget {
638654
builder: (BuildContext context) {
639655
return CustomSingleChildLayout(
640656
delegate: _DropdownMenuRouteLayout<T>(
641-
buttonRect: buttonRect,
642-
route: route,
657+
buttonRect: widget.buttonRect,
658+
route: widget.route,
643659
textDirection: textDirection,
644660
),
645-
child: capturedThemes.wrap(menu),
661+
child: widget.capturedThemes.wrap(menu),
646662
);
647663
},
648664
),
649665
);
650666
}
667+
668+
@override
669+
void dispose() {
670+
_scrollSontroller.dispose();
671+
super.dispose();
672+
}
651673
}
652674

653675
// This widget enables _DropdownRoute to look up the sizes of

packages/flutter/test/material/paginated_data_table_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior;
66
import 'package:flutter/material.dart';
77
import 'package:flutter/rendering.dart';
88
import 'package:flutter_test/flutter_test.dart';
9+
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
910

1011
import 'data_table_test_utils.dart';
1112

@@ -66,7 +67,7 @@ class TestDataSource extends DataTableSource {
6667
void main() {
6768
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
6869

69-
testWidgets('PaginatedDataTable paging', (WidgetTester tester) async {
70+
testWidgetsWithLeakTracking('PaginatedDataTable paging', (WidgetTester tester) async {
7071
final TestDataSource source = TestDataSource();
7172
addTearDown(source.dispose);
7273

0 commit comments

Comments
 (0)