diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index 32fcad2862..f113cad76c 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -673,11 +673,19 @@ class _ViewContentState extends State<_ViewContent> { super.initState(); _viewRect = widget.viewRect; _controller = widget.searchController; + _controller.addListener(updateSuggestions); + if (!_focusNode.hasFocus) { _focusNode.requestFocus(); } } + @override + void dispose(){ + _controller.removeListener(updateSuggestions); + super.dispose(); + } + @override void didUpdateWidget(covariant _ViewContent oldWidget) { super.didUpdateWidget(oldWidget); @@ -737,7 +745,6 @@ class _ViewContentState extends State<_ViewContent> { icon: const Icon(Icons.close), onPressed: () { _controller.clear(); - updateSuggestions(); }, ), ]; diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index 3398560998..aa28559199 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -1490,6 +1490,95 @@ void main() { expect(controller.value.text, suggestion); }); + testWidgets('SearchAnchor should update suggestions on changes to search controller', (WidgetTester tester) async { + final SearchController controller = SearchController(); + const List suggestions = ['foo','far','bim']; + addTearDown(controller.dispose); + + await tester.pumpWidget(MaterialApp( + home: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Material( + child: Align( + alignment: Alignment.topCenter, + child: SearchAnchor( + searchController: controller, + builder: (BuildContext context, SearchController controller) { + return const Icon(Icons.search); + }, + suggestionsBuilder: (BuildContext context, SearchController controller) { + final String searchText = controller.text.toLowerCase(); + if (searchText.isEmpty) { + return const [ + Center( + child: Text('No Search'), + ), + ]; + } + final Iterable filterSuggestions = suggestions.where( + (String suggestion) => suggestion.toLowerCase().contains(searchText), + ); + return filterSuggestions.map((String suggestion) { + return ListTile( + title: Text(suggestion), + trailing: IconButton( + icon: const Icon(Icons.call_missed), + onPressed: () { + controller.text = suggestion; + }, + ), + onTap: () { + controller.closeView(suggestion); + }, + ); + }).toList(); + }, + ), + ), + ); + } + ), + )); + + await tester.tap(find.byIcon(Icons.search)); + await tester.pumpAndSettle(); + + final Finder listTile1 = find.widgetWithText(ListTile, 'foo'); + final Finder listTile2 = find.widgetWithText(ListTile, 'far'); + final Finder listTile3 = find.widgetWithText(ListTile, 'bim'); + final Finder textWidget = find.widgetWithText(Center, 'No Search'); + final Finder iconInListTile1 = find.descendant(of: listTile1, matching: find.byIcon(Icons.call_missed)); + + expect(textWidget,findsOneWidget); + expect(listTile1, findsNothing); + expect(listTile2, findsNothing); + expect(listTile3, findsNothing); + + await tester.enterText(find.byType(SearchBar), 'f'); + await tester.pumpAndSettle(); + expect(textWidget,findsNothing); + expect(listTile1, findsOneWidget); + expect(listTile2, findsOneWidget); + expect(listTile3, findsNothing); + + await tester.tap(iconInListTile1); + await tester.pumpAndSettle(); + expect(controller.value.text, 'foo'); + expect(textWidget,findsNothing); + expect(listTile1, findsOneWidget); + expect(listTile2, findsNothing); + expect(listTile3, findsNothing); + + await tester.tap(listTile1); + await tester.pumpAndSettle(); + expect(controller.isOpen, false); + expect(controller.value.text, 'foo'); + expect(textWidget,findsNothing); + expect(listTile1, findsNothing); + expect(listTile2, findsNothing); + expect(listTile3, findsNothing); + }); + testWidgets('SearchAnchor suggestionsBuilder property could be async', (WidgetTester tester) async { final SearchController controller = SearchController(); const String suggestion = 'suggestion text';