diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index be224979825..fafe76e0304 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -434,13 +434,15 @@ class _DropdownMenuState extends State> { double? leadingPadding; bool _menuHasEnabledItem = false; TextEditingController? _localTextEditingController; - TextEditingController get _textEditingController { - return widget.controller ?? (_localTextEditingController ??= TextEditingController()); - } @override void initState() { super.initState(); + if (widget.controller != null) { + _localTextEditingController = widget.controller; + } else { + _localTextEditingController = TextEditingController(); + } _enableFilter = widget.enableFilter; filteredEntries = widget.dropdownMenuEntries; buttonItemKeys = List.generate(filteredEntries.length, (int index) => GlobalKey()); @@ -448,7 +450,7 @@ class _DropdownMenuState extends State> { final int index = filteredEntries.indexWhere((DropdownMenuEntry entry) => entry.value == widget.initialSelection); if (index != -1) { - _textEditingController.value = TextEditingValue( + _localTextEditingController?.value = TextEditingValue( text: filteredEntries[index].label, selection: TextSelection.collapsed(offset: filteredEntries[index].label.length), ); @@ -458,8 +460,10 @@ class _DropdownMenuState extends State> { @override void dispose() { + if (widget.controller == null) { _localTextEditingController?.dispose(); _localTextEditingController = null; + } super.dispose(); } @@ -469,8 +473,8 @@ class _DropdownMenuState extends State> { if (oldWidget.controller != widget.controller) { if (widget.controller != null) { _localTextEditingController?.dispose(); - _localTextEditingController = null; } + _localTextEditingController = widget.controller ?? TextEditingController(); } if (oldWidget.enableSearch != widget.enableSearch) { if (!widget.enableSearch) { @@ -489,7 +493,7 @@ class _DropdownMenuState extends State> { if (oldWidget.initialSelection != widget.initialSelection) { final int index = filteredEntries.indexWhere((DropdownMenuEntry entry) => entry.value == widget.initialSelection); if (index != -1) { - _textEditingController.value = TextEditingValue( + _localTextEditingController?.value = TextEditingValue( text: filteredEntries[index].label, selection: TextSelection.collapsed(offset: filteredEntries[index].label.length), ); @@ -601,7 +605,7 @@ class _DropdownMenuState extends State> { trailingIcon: entry.trailingIcon, onPressed: entry.enabled ? () { - _textEditingController.value = TextEditingValue( + _localTextEditingController?.value = TextEditingValue( text: entry.label, selection: TextSelection.collapsed(offset: entry.label.length), ); @@ -630,7 +634,7 @@ class _DropdownMenuState extends State> { currentHighlight = (currentHighlight! - 1) % filteredEntries.length; } final String currentLabel = filteredEntries[currentHighlight!].label; - _textEditingController.value = TextEditingValue( + _localTextEditingController?.value = TextEditingValue( text: currentLabel, selection: TextSelection.collapsed(offset: currentLabel.length), ); @@ -649,7 +653,7 @@ class _DropdownMenuState extends State> { currentHighlight = (currentHighlight! + 1) % filteredEntries.length; } final String currentLabel = filteredEntries[currentHighlight!].label; - _textEditingController.value = TextEditingValue( + _localTextEditingController?.value = TextEditingValue( text: currentLabel, selection: TextSelection.collapsed(offset: currentLabel.length), ); @@ -661,7 +665,7 @@ class _DropdownMenuState extends State> { currentHighlight = null; controller.close(); } else { // close to open - if (_textEditingController.text.isNotEmpty) { + if (_localTextEditingController!.text.isNotEmpty) { _enableFilter = false; } controller.open(); @@ -677,14 +681,14 @@ class _DropdownMenuState extends State> { final DropdownMenuThemeData defaults = _DropdownMenuDefaultsM3(context); if (_enableFilter) { - filteredEntries = filter(widget.dropdownMenuEntries, _textEditingController); + filteredEntries = filter(widget.dropdownMenuEntries, _localTextEditingController!); } if (widget.enableSearch) { if (widget.searchCallback != null) { - currentHighlight = widget.searchCallback!.call(filteredEntries, _textEditingController.text); + currentHighlight = widget.searchCallback!.call(filteredEntries, _localTextEditingController!.text); } else { - currentHighlight = search(filteredEntries, _textEditingController); + currentHighlight = search(filteredEntries, _localTextEditingController!); } if (currentHighlight != null) { scrollToHighlight(); @@ -750,12 +754,12 @@ class _DropdownMenuState extends State> { enableInteractiveSelection: canRequestFocus(), textAlignVertical: TextAlignVertical.center, style: effectiveTextStyle, - controller: _textEditingController, + controller: _localTextEditingController, onEditingComplete: () { if (currentHighlight != null) { final DropdownMenuEntry entry = filteredEntries[currentHighlight!]; if (entry.enabled) { - _textEditingController.value = TextEditingValue( + _localTextEditingController?.value = TextEditingValue( text: entry.label, selection: TextSelection.collapsed(offset: entry.label.length), ); diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 106db9be5af..fe2ef9537c8 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -8,11 +8,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_testing/leak_tracker_testing.dart'; void main() { - // TODO(polina-c): _DropdownMenuState should not be used after disposal, https://github.com/flutter/flutter/issues/145622 [leaks-to-clean] - LeakTesting.settings = LeakTesting.settings.withIgnoredAll(); const String longText = 'one two three four five six seven eight nine ten eleven twelve'; final List> menuChildren = >[]; @@ -2070,6 +2067,7 @@ void main() { }, ); final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp(