SearchBar should listen to changes to the SearchController and update suggestions on change (#134337)
This PR is adding a listener to the `SearchController`, so that the `suggestionBuilder` can be updated when the `SearchController` changes. Another method we can possibly do is have an update method on `SearchController`, so that the user can manually update the suggestions instead of us doing it automatically. Fixes #132161
This commit is contained in:
parent
3e60999b11
commit
d9c0d3ae51
@ -673,11 +673,19 @@ class _ViewContentState extends State<_ViewContent> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
_viewRect = widget.viewRect;
|
_viewRect = widget.viewRect;
|
||||||
_controller = widget.searchController;
|
_controller = widget.searchController;
|
||||||
|
_controller.addListener(updateSuggestions);
|
||||||
|
|
||||||
if (!_focusNode.hasFocus) {
|
if (!_focusNode.hasFocus) {
|
||||||
_focusNode.requestFocus();
|
_focusNode.requestFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose(){
|
||||||
|
_controller.removeListener(updateSuggestions);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant _ViewContent oldWidget) {
|
void didUpdateWidget(covariant _ViewContent oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
@ -737,7 +745,6 @@ class _ViewContentState extends State<_ViewContent> {
|
|||||||
icon: const Icon(Icons.close),
|
icon: const Icon(Icons.close),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_controller.clear();
|
_controller.clear();
|
||||||
updateSuggestions();
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@ -1490,6 +1490,95 @@ void main() {
|
|||||||
expect(controller.value.text, suggestion);
|
expect(controller.value.text, suggestion);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('SearchAnchor should update suggestions on changes to search controller', (WidgetTester tester) async {
|
||||||
|
final SearchController controller = SearchController();
|
||||||
|
const List<String> suggestions = <String>['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 <Widget>[
|
||||||
|
Center(
|
||||||
|
child: Text('No Search'),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
final Iterable<String> 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 {
|
testWidgets('SearchAnchor suggestionsBuilder property could be async', (WidgetTester tester) async {
|
||||||
final SearchController controller = SearchController();
|
final SearchController controller = SearchController();
|
||||||
const String suggestion = 'suggestion text';
|
const String suggestion = 'suggestion text';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user