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>({
/// for another [showSearch] call.
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
/// query into the search field.
///
......@@ -225,6 +259,22 @@ abstract class SearchDelegate<T> {
..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.
///
/// This animation is commonly used to animate [AnimatedIcon]s of
......@@ -417,7 +467,8 @@ class _SearchPageState<T> extends State<_SearchPage<T>> {
Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(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;
switch(widget.delegate._currentBody) {
case _SearchBody.suggestions:
......@@ -459,7 +510,8 @@ class _SearchPageState<T> extends State<_SearchPage<T>> {
controller: widget.delegate._queryTextController,
focusNode: focusNode,
style: theme.textTheme.title,
textInputAction: TextInputAction.search,
textInputAction: widget.delegate.textInputAction,
keyboardType: widget.delegate.keyboardType,
onSubmitted: (String _) {
widget.delegate.showResults(context);
},
......
......@@ -479,7 +479,37 @@ void main() {
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();
await tester.pumpWidget(TestHomePage(
......@@ -493,6 +523,18 @@ void main() {
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', () {
TestSemantics buildExpected({ String routeName }) {
return TestSemantics.root(
......@@ -649,12 +691,13 @@ class TestHomePage extends StatelessWidget {
}
class _TestSearchDelegate extends SearchDelegate<String> {
_TestSearchDelegate({
this.suggestions = 'Suggestions',
this.result = 'Result',
this.actions = const <Widget>[],
});
String searchHint,
TextInputAction textInputAction = TextInputAction.search,
}) : super(searchFieldLabel: searchHint, textInputAction: textInputAction);
final String suggestions;
final String result;
......@@ -704,4 +747,4 @@ class _TestSearchDelegate extends SearchDelegate<String> {
List<Widget> buildActions(BuildContext context) {
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