Added keyboardType & textInputAction props to SearchBar, SearchAnchor & SearchAnchor.bar (#138553)
Added `keyboardType` & `textInputAction` props to `SearchBar`, `SearchAnchor` & `SearchAnchor.bar` Fixes #138483
This commit is contained in:
@@ -131,6 +131,8 @@ class SearchAnchor extends StatefulWidget {
|
||||
this.viewOnSubmitted,
|
||||
required this.builder,
|
||||
required this.suggestionsBuilder,
|
||||
this.textInputAction,
|
||||
this.keyboardType,
|
||||
});
|
||||
|
||||
/// Create a [SearchAnchor] that has a [SearchBar] which opens a search view.
|
||||
@@ -174,7 +176,9 @@ class SearchAnchor extends StatefulWidget {
|
||||
bool? isFullScreen,
|
||||
SearchController searchController,
|
||||
TextCapitalization textCapitalization,
|
||||
required SuggestionsBuilder suggestionsBuilder
|
||||
required SuggestionsBuilder suggestionsBuilder,
|
||||
TextInputAction? textInputAction,
|
||||
TextInputType? keyboardType,
|
||||
}) = _SearchAnchorWithSearchBar;
|
||||
|
||||
/// Whether the search view grows to fill the entire screen when the
|
||||
@@ -323,6 +327,14 @@ class SearchAnchor extends StatefulWidget {
|
||||
/// To get a different layout, use [viewBuilder] to override.
|
||||
final SuggestionsBuilder suggestionsBuilder;
|
||||
|
||||
/// {@macro flutter.widgets.TextField.textInputAction}
|
||||
final TextInputAction? textInputAction;
|
||||
|
||||
/// The type of action button to use for the keyboard.
|
||||
///
|
||||
/// Defaults to the default value specified in [TextField].
|
||||
final TextInputType? keyboardType;
|
||||
|
||||
@override
|
||||
State<SearchAnchor> createState() => _SearchAnchorState();
|
||||
}
|
||||
@@ -396,6 +408,8 @@ class _SearchAnchorState extends State<SearchAnchor> {
|
||||
suggestionsBuilder: widget.suggestionsBuilder,
|
||||
textCapitalization: widget.textCapitalization,
|
||||
capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
|
||||
textInputAction: widget.textInputAction,
|
||||
keyboardType: widget.keyboardType,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -469,6 +483,8 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
|
||||
required this.searchController,
|
||||
required this.suggestionsBuilder,
|
||||
required this.capturedThemes,
|
||||
this.textInputAction,
|
||||
this.keyboardType,
|
||||
});
|
||||
|
||||
final ValueChanged<String>? viewOnChanged;
|
||||
@@ -494,6 +510,8 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
|
||||
final SearchController searchController;
|
||||
final SuggestionsBuilder suggestionsBuilder;
|
||||
final CapturedThemes capturedThemes;
|
||||
final TextInputAction? textInputAction;
|
||||
final TextInputType? keyboardType;
|
||||
|
||||
@override
|
||||
Color? get barrierColor => Colors.transparent;
|
||||
@@ -637,6 +655,8 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
|
||||
searchController: searchController,
|
||||
suggestionsBuilder: suggestionsBuilder,
|
||||
textCapitalization: textCapitalization,
|
||||
textInputAction: textInputAction,
|
||||
keyboardType: keyboardType,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -673,6 +693,8 @@ class _ViewContent extends StatefulWidget {
|
||||
required this.viewRect,
|
||||
required this.searchController,
|
||||
required this.suggestionsBuilder,
|
||||
this.textInputAction,
|
||||
this.keyboardType,
|
||||
});
|
||||
|
||||
final ValueChanged<String>? viewOnChanged;
|
||||
@@ -697,6 +719,8 @@ class _ViewContent extends StatefulWidget {
|
||||
final Rect viewRect;
|
||||
final SearchController searchController;
|
||||
final SuggestionsBuilder suggestionsBuilder;
|
||||
final TextInputAction? textInputAction;
|
||||
final TextInputType? keyboardType;
|
||||
|
||||
@override
|
||||
State<_ViewContent> createState() => _ViewContentState();
|
||||
@@ -876,6 +900,8 @@ class _ViewContentState extends State<_ViewContent> {
|
||||
},
|
||||
onSubmitted: widget.viewOnSubmitted,
|
||||
textCapitalization: widget.textCapitalization,
|
||||
textInputAction: widget.textInputAction,
|
||||
keyboardType: widget.keyboardType,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -939,7 +965,9 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
|
||||
super.textCapitalization,
|
||||
ValueChanged<String>? onChanged,
|
||||
ValueChanged<String>? onSubmitted,
|
||||
required super.suggestionsBuilder
|
||||
required super.suggestionsBuilder,
|
||||
super.textInputAction,
|
||||
super.keyboardType,
|
||||
}) : super(
|
||||
viewHintText: viewHintText ?? barHintText,
|
||||
headerTextStyle: viewHeaderTextStyle,
|
||||
@@ -970,6 +998,8 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
|
||||
leading: barLeading ?? const Icon(Icons.search),
|
||||
trailing: barTrailing,
|
||||
textCapitalization: textCapitalization,
|
||||
textInputAction: textInputAction,
|
||||
keyboardType: keyboardType,
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -1086,6 +1116,8 @@ class SearchBar extends StatefulWidget {
|
||||
this.hintStyle,
|
||||
this.textCapitalization,
|
||||
this.autoFocus = false,
|
||||
this.textInputAction,
|
||||
this.keyboardType,
|
||||
});
|
||||
|
||||
/// Controls the text being edited in the search bar's text field.
|
||||
@@ -1210,6 +1242,14 @@ class SearchBar extends StatefulWidget {
|
||||
/// {@macro flutter.widgets.editableText.autofocus}
|
||||
final bool autoFocus;
|
||||
|
||||
/// {@macro flutter.widgets.TextField.textInputAction}
|
||||
final TextInputAction? textInputAction;
|
||||
|
||||
/// The type of action button to use for the keyboard.
|
||||
///
|
||||
/// Defaults to the default value specified in [TextField].
|
||||
final TextInputType? keyboardType;
|
||||
|
||||
@override
|
||||
State<SearchBar> createState() => _SearchBarState();
|
||||
}
|
||||
@@ -1349,6 +1389,8 @@ class _SearchBarState extends State<SearchBar> {
|
||||
isDense: true,
|
||||
)),
|
||||
textCapitalization: effectiveTextCapitalization,
|
||||
textInputAction: widget.textInputAction,
|
||||
keyboardType: widget.keyboardType,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -419,10 +419,12 @@ class TextField extends StatefulWidget {
|
||||
/// {@macro flutter.widgets.editableText.keyboardType}
|
||||
final TextInputType keyboardType;
|
||||
|
||||
/// {@template flutter.widgets.TextField.textInputAction}
|
||||
/// The type of action button to use for the keyboard.
|
||||
///
|
||||
/// Defaults to [TextInputAction.newline] if [keyboardType] is
|
||||
/// [TextInputType.multiline] and [TextInputAction.done] otherwise.
|
||||
/// {@endtemplate}
|
||||
final TextInputAction? textInputAction;
|
||||
|
||||
/// {@macro flutter.widgets.editableText.textCapitalization}
|
||||
|
||||
@@ -2762,6 +2762,190 @@ void main() {
|
||||
).first);
|
||||
expect(suggestionMaterial.color, localTheme.cardTheme.color);
|
||||
});
|
||||
|
||||
testWidgetsWithLeakTracking('SearchBar respects keyboardType property', (WidgetTester tester) async {
|
||||
Widget buildSearchBar(TextInputType keyboardType) {
|
||||
return MaterialApp(
|
||||
home: Center(
|
||||
child: Material(
|
||||
child: SearchBar(
|
||||
keyboardType: keyboardType,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildSearchBar(TextInputType.number));
|
||||
await tester.pump();
|
||||
TextField textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.keyboardType, TextInputType.number);
|
||||
|
||||
await tester.pumpWidget(buildSearchBar(TextInputType.phone));
|
||||
await tester.pump();
|
||||
textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.keyboardType, TextInputType.phone);
|
||||
});
|
||||
|
||||
testWidgetsWithLeakTracking('SearchAnchor respects keyboardType property', (WidgetTester tester) async {
|
||||
Widget buildSearchAnchor(TextInputType keyboardType) {
|
||||
return MaterialApp(
|
||||
home: Center(
|
||||
child: Material(
|
||||
child: SearchAnchor(
|
||||
keyboardType: keyboardType,
|
||||
builder: (BuildContext context, SearchController controller) {
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.ac_unit),
|
||||
onPressed: () {
|
||||
controller.openView();
|
||||
},
|
||||
);
|
||||
},
|
||||
suggestionsBuilder: (BuildContext context, SearchController controller) {
|
||||
return <Widget>[];
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildSearchAnchor(TextInputType.number));
|
||||
await tester.pump();
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.ac_unit));
|
||||
await tester.pumpAndSettle();
|
||||
TextField textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.keyboardType, TextInputType.number);
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_back));
|
||||
await tester.pump();
|
||||
|
||||
await tester.pumpWidget(buildSearchAnchor(TextInputType.phone));
|
||||
await tester.pump();
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.ac_unit));
|
||||
await tester.pumpAndSettle();
|
||||
textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.keyboardType, TextInputType.phone);
|
||||
});
|
||||
|
||||
testWidgetsWithLeakTracking('SearchAnchor.bar respects keyboardType property', (WidgetTester tester) async {
|
||||
Widget buildSearchAnchor(TextInputType keyboardType) {
|
||||
return MaterialApp(
|
||||
home: Center(
|
||||
child: Material(
|
||||
child: SearchAnchor.bar(
|
||||
keyboardType: keyboardType,
|
||||
suggestionsBuilder: (BuildContext context, SearchController controller) {
|
||||
return <Widget>[];
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildSearchAnchor(TextInputType.number));
|
||||
await tester.pump();
|
||||
await tester.tap(find.byType(SearchBar)); // Open search view.
|
||||
await tester.pumpAndSettle();
|
||||
final Finder textFieldFinder = find.descendant(of: findViewContent(), matching: find.byType(TextField));
|
||||
final TextField textFieldInView = tester.widget<TextField>(textFieldFinder);
|
||||
expect(textFieldInView.keyboardType, TextInputType.number);
|
||||
// Close search view.
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
final TextField textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.keyboardType, TextInputType.number);
|
||||
});
|
||||
|
||||
testWidgetsWithLeakTracking('SearchBar respects textInputAction property', (WidgetTester tester) async {
|
||||
Widget buildSearchBar(TextInputAction textInputAction) {
|
||||
return MaterialApp(
|
||||
home: Center(
|
||||
child: Material(
|
||||
child: SearchBar(
|
||||
textInputAction: textInputAction,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildSearchBar(TextInputAction.previous));
|
||||
await tester.pump();
|
||||
TextField textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.textInputAction, TextInputAction.previous);
|
||||
|
||||
await tester.pumpWidget(buildSearchBar(TextInputAction.send));
|
||||
await tester.pump();
|
||||
textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.textInputAction, TextInputAction.send);
|
||||
});
|
||||
|
||||
testWidgetsWithLeakTracking('SearchAnchor respects textInputAction property', (WidgetTester tester) async {
|
||||
Widget buildSearchAnchor(TextInputAction textInputAction) {
|
||||
return MaterialApp(
|
||||
home: Center(
|
||||
child: Material(
|
||||
child: SearchAnchor(
|
||||
textInputAction: textInputAction,
|
||||
builder: (BuildContext context, SearchController controller) {
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.ac_unit),
|
||||
onPressed: () {
|
||||
controller.openView();
|
||||
},
|
||||
);
|
||||
},
|
||||
suggestionsBuilder: (BuildContext context, SearchController controller) {
|
||||
return <Widget>[];
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildSearchAnchor(TextInputAction.previous));
|
||||
await tester.pump();
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.ac_unit));
|
||||
await tester.pumpAndSettle();
|
||||
TextField textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.textInputAction, TextInputAction.previous);
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_back));
|
||||
await tester.pump();
|
||||
|
||||
await tester.pumpWidget(buildSearchAnchor(TextInputAction.send));
|
||||
await tester.pump();
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.ac_unit));
|
||||
await tester.pumpAndSettle();
|
||||
textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.textInputAction, TextInputAction.send);
|
||||
});
|
||||
|
||||
testWidgetsWithLeakTracking('SearchAnchor.bar respects textInputAction property', (WidgetTester tester) async {
|
||||
Widget buildSearchAnchor(TextInputAction textInputAction) {
|
||||
return MaterialApp(
|
||||
home: Center(
|
||||
child: Material(
|
||||
child: SearchAnchor.bar(
|
||||
textInputAction: textInputAction,
|
||||
suggestionsBuilder: (BuildContext context, SearchController controller) {
|
||||
return <Widget>[];
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pumpWidget(buildSearchAnchor(TextInputAction.previous));
|
||||
await tester.pump();
|
||||
await tester.tap(find.byType(SearchBar)); // Open search view.
|
||||
await tester.pumpAndSettle();
|
||||
final Finder textFieldFinder = find.descendant(of: findViewContent(), matching: find.byType(TextField));
|
||||
final TextField textFieldInView = tester.widget<TextField>(textFieldFinder);
|
||||
expect(textFieldInView.textInputAction, TextInputAction.previous);
|
||||
// Close search view.
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
final TextField textField = tester.widget(find.byType(TextField));
|
||||
expect(textField.textInputAction, TextInputAction.previous);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> checkSearchBarDefaults(WidgetTester tester, ColorScheme colorScheme, Material material) async {
|
||||
|
||||
Reference in New Issue
Block a user