Commit 9f083162 authored by knaeckeKami's avatar knaeckeKami Committed by Shi-Hao Hong

Add searchFieldLabel to SearchDelegate in order to show a custom hint (#36409)

* Add searchFieldLabel to SearchDelegate in order to show a custom hint label.

* Add support for specifying textInputAction and keyboardType in SearchDelegate
parent b2497822
...@@ -89,6 +89,40 @@ Future<T> showSearch<T>({ ...@@ -89,6 +89,40 @@ Future<T> showSearch<T>({
/// for another [showSearch] call. /// for another [showSearch] call.
abstract class SearchDelegate<T> { abstract class SearchDelegate<T> {
/// Constructor to be called by subclasses which may specify [searchFieldLabel], [keyboardType] and/or
/// [textInputAction].
///
/// {@tool sample}
/// ```dart
/// class CustomSearchHintDelegate extends SearchDelegate {
/// CustomSearchHintDelegate({
/// String hintText,
/// }) : super(
/// searchFieldLabel: hintText,
/// keyboardType: TextInputType.text,
/// textInputAction: TextInputAction.search,
/// );
///
/// @override
/// Widget buildLeading(BuildContext context) => Text("leading");
///
/// @override
/// Widget buildSuggestions(BuildContext context) => Text("suggestions");
///
/// @override
/// Widget buildResults(BuildContext context) => Text('results');
///
/// @override
/// List<Widget> buildActions(BuildContext context) => [];
/// }
/// ```
/// {@end-tool}
SearchDelegate({
this.searchFieldLabel,
this.keyboardType,
this.textInputAction = TextInputAction.search,
});
/// Suggestions shown in the body of the search page while the user types a /// Suggestions shown in the body of the search page while the user types a
/// query into the search field. /// query into the search field.
/// ///
...@@ -225,6 +259,22 @@ abstract class SearchDelegate<T> { ...@@ -225,6 +259,22 @@ abstract class SearchDelegate<T> {
..pop(result); ..pop(result);
} }
/// The hint text that is shown in the search field when it is empty.
///
/// If this value is set to null, the value of MaterialLocalizations.of(context).searchFieldLabel will be used instead.
final String searchFieldLabel;
/// The type of action button to use for the keyboard.
///
/// Defaults to the default value specified in [TextField].
final TextInputType keyboardType;
/// The text input action configuring the soft keyboard to a particular action
/// button.
///
/// Defaults to [TextInputAction.search].
final TextInputAction textInputAction;
/// [Animation] triggered when the search pages fades in or out. /// [Animation] triggered when the search pages fades in or out.
/// ///
/// This animation is commonly used to animate [AnimatedIcon]s of /// This animation is commonly used to animate [AnimatedIcon]s of
...@@ -417,7 +467,8 @@ class _SearchPageState<T> extends State<_SearchPage<T>> { ...@@ -417,7 +467,8 @@ class _SearchPageState<T> extends State<_SearchPage<T>> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
final ThemeData theme = widget.delegate.appBarTheme(context); final ThemeData theme = widget.delegate.appBarTheme(context);
final String searchFieldLabel = MaterialLocalizations.of(context).searchFieldLabel; final String searchFieldLabel = widget.delegate.searchFieldLabel
?? MaterialLocalizations.of(context).searchFieldLabel;
Widget body; Widget body;
switch(widget.delegate._currentBody) { switch(widget.delegate._currentBody) {
case _SearchBody.suggestions: case _SearchBody.suggestions:
...@@ -459,7 +510,8 @@ class _SearchPageState<T> extends State<_SearchPage<T>> { ...@@ -459,7 +510,8 @@ class _SearchPageState<T> extends State<_SearchPage<T>> {
controller: widget.delegate._queryTextController, controller: widget.delegate._queryTextController,
focusNode: focusNode, focusNode: focusNode,
style: theme.textTheme.title, style: theme.textTheme.title,
textInputAction: TextInputAction.search, textInputAction: widget.delegate.textInputAction,
keyboardType: widget.delegate.keyboardType,
onSubmitted: (String _) { onSubmitted: (String _) {
widget.delegate.showResults(context); widget.delegate.showResults(context);
}, },
......
...@@ -479,7 +479,37 @@ void main() { ...@@ -479,7 +479,37 @@ void main() {
expect(selectedResults, <String>['Result Foo']); expect(selectedResults, <String>['Result Foo']);
}); });
testWidgets('keyboard show search button', (WidgetTester tester) async { testWidgets('Custom searchFieldLabel value', (WidgetTester tester) async {
const String searchHint = 'custom search hint';
final String defaultSearchHint = const DefaultMaterialLocalizations().searchFieldLabel;
final _TestSearchDelegate delegate = _TestSearchDelegate(searchHint: searchHint);
await tester.pumpWidget(TestHomePage(
delegate: delegate,
));
await tester.tap(find.byTooltip('Search'));
await tester.pumpAndSettle();
expect(find.text(searchHint), findsOneWidget);
expect(find.text(defaultSearchHint), findsNothing);
});
testWidgets('Default searchFieldLabel is used when it is set to null', (WidgetTester tester) async {
final String searchHint = const DefaultMaterialLocalizations().searchFieldLabel;
final _TestSearchDelegate delegate = _TestSearchDelegate();
await tester.pumpWidget(TestHomePage(
delegate: delegate,
));
await tester.tap(find.byTooltip('Search'));
await tester.pumpAndSettle();
expect(find.text(searchHint), findsOneWidget);
});
testWidgets('keyboard show search button by default', (WidgetTester tester) async {
final _TestSearchDelegate delegate = _TestSearchDelegate(); final _TestSearchDelegate delegate = _TestSearchDelegate();
await tester.pumpWidget(TestHomePage( await tester.pumpWidget(TestHomePage(
...@@ -493,6 +523,18 @@ void main() { ...@@ -493,6 +523,18 @@ void main() {
expect(tester.testTextInput.setClientArgs['inputAction'], TextInputAction.search.toString()); expect(tester.testTextInput.setClientArgs['inputAction'], TextInputAction.search.toString());
}); });
testWidgets('Custom textInputAction results in keyboard with corresponding button', (WidgetTester tester) async {
final _TestSearchDelegate delegate = _TestSearchDelegate(textInputAction: TextInputAction.done);
await tester.pumpWidget(TestHomePage(
delegate: delegate,
));
await tester.tap(find.byTooltip('Search'));
await tester.pumpAndSettle();
await tester.showKeyboard(find.byType(TextField));
expect(tester.testTextInput.setClientArgs['inputAction'], TextInputAction.done.toString());
});
group('contributes semantics', () { group('contributes semantics', () {
TestSemantics buildExpected({ String routeName }) { TestSemantics buildExpected({ String routeName }) {
return TestSemantics.root( return TestSemantics.root(
...@@ -649,12 +691,13 @@ class TestHomePage extends StatelessWidget { ...@@ -649,12 +691,13 @@ class TestHomePage extends StatelessWidget {
} }
class _TestSearchDelegate extends SearchDelegate<String> { class _TestSearchDelegate extends SearchDelegate<String> {
_TestSearchDelegate({ _TestSearchDelegate({
this.suggestions = 'Suggestions', this.suggestions = 'Suggestions',
this.result = 'Result', this.result = 'Result',
this.actions = const <Widget>[], this.actions = const <Widget>[],
}); String searchHint,
TextInputAction textInputAction = TextInputAction.search,
}) : super(searchFieldLabel: searchHint, textInputAction: textInputAction);
final String suggestions; final String suggestions;
final String result; final String result;
...@@ -704,4 +747,4 @@ class _TestSearchDelegate extends SearchDelegate<String> { ...@@ -704,4 +747,4 @@ class _TestSearchDelegate extends SearchDelegate<String> {
List<Widget> buildActions(BuildContext context) { List<Widget> buildActions(BuildContext context) {
return actions; return actions;
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment