diff --git a/packages/dropdown_button2/CHANGELOG.md b/packages/dropdown_button2/CHANGELOG.md index fc3832a..7d87afa 100644 --- a/packages/dropdown_button2/CHANGELOG.md +++ b/packages/dropdown_button2/CHANGELOG.md @@ -1,6 +1,7 @@ ## UNRELEASED - Fix errorStyle has no effect for DropdownButtonFormField2, closes #327. +- DropdownRoutePage should dispose the created ScrollController [Flutter core]. ## 3.0.0-beta.21 diff --git a/packages/dropdown_button2/lib/src/dropdown_menu.dart b/packages/dropdown_button2/lib/src/dropdown_menu.dart index 87cee62..15279a8 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu.dart @@ -17,6 +17,7 @@ class _DropdownMenu extends StatefulWidget { const _DropdownMenu({ super.key, required this.route, + required this.scrollController, required this.textDirection, required this.buttonRect, required this.constraints, @@ -25,6 +26,7 @@ class _DropdownMenu extends StatefulWidget { }); final _DropdownRoute route; + final ScrollController scrollController; final TextDirection? textDirection; final Rect buttonRect; final BoxConstraints constraints; @@ -50,6 +52,7 @@ class _DropdownMenuState extends State<_DropdownMenu> { _DropdownItemButton dropdownItemButton(int index) => _DropdownItemButton( route: widget.route, + scrollController: widget.scrollController, textDirection: widget.textDirection, buttonRect: widget.buttonRect, constraints: widget.constraints, @@ -177,7 +180,7 @@ class _DropdownMenuState extends State<_DropdownMenu> { platform: Theme.of(context).platform, ), child: PrimaryScrollController( - controller: route.scrollController!, + controller: widget.scrollController, child: Theme( data: Theme.of(context).copyWith( scrollbarTheme: dropdownStyle.scrollbarTheme, diff --git a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart index aea156a..b1e999f 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart @@ -124,6 +124,7 @@ class _DropdownItemButton extends StatefulWidget { const _DropdownItemButton({ super.key, required this.route, + required this.scrollController, required this.textDirection, required this.buttonRect, required this.constraints, @@ -133,6 +134,7 @@ class _DropdownItemButton extends StatefulWidget { }); final _DropdownRoute route; + final ScrollController scrollController; final TextDirection? textDirection; final Rect buttonRect; final BoxConstraints constraints; @@ -163,7 +165,7 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { widget.mediaQueryPadding, widget.itemIndex, ); - widget.route.scrollController!.animateTo( + widget.scrollController.animateTo( menuLimits.scrollOffset, curve: Curves.easeInOut, duration: const Duration(milliseconds: 100), diff --git a/packages/dropdown_button2/lib/src/dropdown_route.dart b/packages/dropdown_button2/lib/src/dropdown_route.dart index 898ed4d..6286818 100644 --- a/packages/dropdown_button2/lib/src/dropdown_route.dart +++ b/packages/dropdown_button2/lib/src/dropdown_route.dart @@ -36,8 +36,6 @@ class _DropdownRoute extends PopupRoute<_DropdownRouteResult> { final DropdownSearchData? searchData; final DropdownSeparator? dropdownSeparator; - ScrollController? scrollController; - @override Duration get transitionDuration => _kDropdownMenuDuration; @@ -250,7 +248,7 @@ class _DropdownRoute extends PopupRoute<_DropdownRouteResult> { } } -class _DropdownRoutePage extends StatelessWidget { +class _DropdownRoutePage extends StatefulWidget { const _DropdownRoutePage({ super.key, required this.route, @@ -275,35 +273,50 @@ class _DropdownRoutePage extends StatelessWidget { final bool enableFeedback; @override - Widget build(BuildContext context) { - assert(debugCheckHasDirectionality(context)); + State<_DropdownRoutePage> createState() => _DropdownRoutePageState(); +} + +class _DropdownRoutePageState extends State<_DropdownRoutePage> { + late ScrollController _scrollController; + @override + void initState() { + super.initState(); // Computing the initialScrollOffset now, before the items have been laid // out. This only works if the item heights are effectively fixed, i.e. either // DropdownButton.itemHeight is specified or DropdownButton.itemHeight is null // and all of the items' intrinsic heights are less than _kMenuItemHeight. // Otherwise the initialScrollOffset is just a rough approximation based on // treating the items as if their heights were all equal to _kMenuItemHeight. - if (route.scrollController == null) { - final _MenuLimits menuLimits = route.getMenuLimits( - buttonRect, - constraints.maxHeight, - mediaQueryPadding, - selectedIndex, - ); - route.scrollController = - ScrollController(initialScrollOffset: menuLimits.scrollOffset); - } + final _MenuLimits menuLimits = widget.route.getMenuLimits( + widget.buttonRect, + widget.constraints.maxHeight, + widget.mediaQueryPadding, + widget.selectedIndex, + ); + _scrollController = + ScrollController(initialScrollOffset: menuLimits.scrollOffset); + } - final TextDirection? textDirection = Directionality.maybeOf(context); + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + @override + Widget build(BuildContext context) { + assert(debugCheckHasDirectionality(context)); + + final TextDirection? textDirection = Directionality.maybeOf(context); final Widget menu = _DropdownMenu( - route: route, + route: widget.route, + scrollController: _scrollController, textDirection: textDirection, - buttonRect: buttonRect, - constraints: constraints, - mediaQueryPadding: mediaQueryPadding, - enableFeedback: enableFeedback, + buttonRect: widget.buttonRect, + constraints: widget.constraints, + mediaQueryPadding: widget.mediaQueryPadding, + enableFeedback: widget.enableFeedback, ); return MediaQuery.removePadding( @@ -316,13 +329,13 @@ class _DropdownRoutePage extends StatelessWidget { builder: (BuildContext context) { return CustomSingleChildLayout( delegate: _DropdownMenuRouteLayout( - route: route, + route: widget.route, textDirection: textDirection, - buttonRect: buttonRect, - availableHeight: constraints.maxHeight, - mediaQueryPadding: mediaQueryPadding, + buttonRect: widget.buttonRect, + availableHeight: widget.constraints.maxHeight, + mediaQueryPadding: widget.mediaQueryPadding, ), - child: capturedThemes.wrap(menu), + child: widget.capturedThemes.wrap(menu), ); }, ),