SearchAnchor viewOnClose (#160892)

Fixes https://github.com/flutter/flutter/issues/160891

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com>
This commit is contained in:
Gianluca Bettega 2025-02-05 18:02:37 -03:00 committed by GitHub
parent e78f135e36
commit 1fecd2bd79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 97 additions and 0 deletions

View File

@ -146,6 +146,7 @@ class SearchAnchor extends StatefulWidget {
this.textCapitalization,
this.viewOnChanged,
this.viewOnSubmitted,
this.viewOnClose,
required this.builder,
required this.suggestionsBuilder,
this.textInputAction,
@ -171,6 +172,7 @@ class SearchAnchor extends StatefulWidget {
GestureTapCallback? onTap,
ValueChanged<String>? onSubmitted,
ValueChanged<String>? onChanged,
VoidCallback? onClose,
MaterialStateProperty<double?>? barElevation,
MaterialStateProperty<Color?>? barBackgroundColor,
MaterialStateProperty<Color?>? barOverlayColor,
@ -370,6 +372,9 @@ class SearchAnchor extends StatefulWidget {
/// of the search view.
final ValueChanged<String>? viewOnSubmitted;
/// Called when the search view is closed.
final VoidCallback? viewOnClose;
/// Called to create a widget which can open a search view route when it is tapped.
///
/// The widget returned by this builder is faded out when it is tapped.
@ -459,6 +464,7 @@ class _SearchAnchorState extends State<SearchAnchor> {
_route = _SearchViewRoute(
viewOnChanged: widget.viewOnChanged,
viewOnSubmitted: widget.viewOnSubmitted,
viewOnClose: widget.viewOnClose,
viewLeading: widget.viewLeading,
viewTrailing: widget.viewTrailing,
viewHintText: widget.viewHintText,
@ -537,6 +543,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
_SearchViewRoute({
this.viewOnChanged,
this.viewOnSubmitted,
this.viewOnClose,
this.toggleVisibility,
this.textDirection,
this.viewBuilder,
@ -568,6 +575,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
final ValueChanged<String>? viewOnChanged;
final ValueChanged<String>? viewOnSubmitted;
final VoidCallback? viewOnClose;
final ValueGetter<bool>? toggleVisibility;
final TextDirection? textDirection;
final ViewBuilder? viewBuilder;
@ -641,6 +649,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
assert(anchorKey.currentContext != null);
updateTweens(anchorKey.currentContext!);
toggleVisibility?.call();
viewOnClose?.call();
return super.didPop(result);
}
@ -1183,6 +1192,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
super.textCapitalization,
ValueChanged<String>? onChanged,
ValueChanged<String>? onSubmitted,
VoidCallback? onClose,
required super.suggestionsBuilder,
super.textInputAction,
super.keyboardType,
@ -1196,6 +1206,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
headerHintStyle: viewHeaderHintStyle,
viewOnSubmitted: onSubmitted,
viewOnChanged: onChanged,
viewOnClose: onClose,
builder: (BuildContext context, SearchController controller) {
return SearchBar(
constraints: constraints,

View File

@ -3829,6 +3829,92 @@ void main() {
await tester.pump();
expect(tester.takeException(), isNull);
});
testWidgets('SearchAnchor viewOnClose function test', (WidgetTester tester) async {
String name = 'silva';
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: SearchAnchor(
viewOnClose: () {
name = 'Pedro';
},
builder: (BuildContext context, SearchController controller) {
return IconButton(
icon: const Icon(Icons.search),
onPressed: () {
controller.openView();
},
);
},
suggestionsBuilder: (BuildContext context, SearchController controller) {
return List<Widget>.generate(5, (int index) {
final String item = 'item $index';
return ListTile(
leading: const Icon(Icons.history),
title: Text(item),
trailing: const Icon(Icons.chevron_right),
onTap: () {},
);
});
},
),
),
),
),
);
// Open search view
await tester.tap(find.byIcon(Icons.search));
await tester.pumpAndSettle();
expect(name, 'silva');
// Pop search view route
await tester.tap(find.backButton());
await tester.pumpAndSettle();
expect(name, 'Pedro');
// No exception.
});
testWidgets('SearchAnchor.bar viewOnClose function test', (WidgetTester tester) async {
String name = 'silva';
await tester.pumpWidget(
MaterialApp(
home: Material(
child: SearchAnchor.bar(
onClose: () {
name = 'Pedro';
},
suggestionsBuilder: (BuildContext context, SearchController controller) {
return <Widget>[
ListTile(
title: const Text('item 0'),
onTap: () {
controller.closeView('item 0');
},
),
];
},
),
),
),
);
// Open search view
await tester.tap(find.byType(SearchBar));
await tester.pumpAndSettle();
expect(name, 'silva');
// Pop search view route
await tester.tap(find.backButton());
await tester.pumpAndSettle();
expect(name, 'Pedro');
// No exception.
});
}
Future<void> checkSearchBarDefaults(