Add headerHeight for SearchAnchor (#141223)

Fixes #140046

This PR is to add a `headerHeight` property to `SearchAnchor` and `SearchViewThemeData` so the header height on the search view can be customized.
This commit is contained in:
Qun Cheng 2024-01-17 22:49:04 +00:00 committed by GitHub
parent a3c11cdc66
commit ef794e2a28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 89 additions and 4 deletions

View file

@ -123,6 +123,7 @@ class SearchAnchor extends StatefulWidget {
this.viewSurfaceTintColor,
this.viewSide,
this.viewShape,
this.headerHeight,
this.headerTextStyle,
this.headerHintStyle,
this.dividerColor,
@ -169,6 +170,7 @@ class SearchAnchor extends StatefulWidget {
double? viewElevation,
BorderSide? viewSide,
OutlinedBorder? viewShape,
double? viewHeaderHeight,
TextStyle? viewHeaderTextStyle,
TextStyle? viewHeaderHintStyle,
Color? dividerColor,
@ -261,6 +263,12 @@ class SearchAnchor extends StatefulWidget {
/// mode and a [RoundedRectangleBorder] shape with a 28.0 radius otherwise.
final OutlinedBorder? viewShape;
/// The height of the search field on the search view.
///
/// If null, the value of [SearchViewThemeData.headerHeight] will be used. If
/// this is also null, the default value is 56.0.
final double? headerHeight;
/// The style to use for the text being edited on the search view.
///
/// If null, defaults to the `bodyLarge` text style from the current [Theme].
@ -396,6 +404,7 @@ class _SearchAnchorState extends State<SearchAnchor> {
viewSurfaceTintColor: widget.viewSurfaceTintColor,
viewSide: widget.viewSide,
viewShape: widget.viewShape,
viewHeaderHeight: widget.headerHeight,
viewHeaderTextStyle: widget.headerTextStyle,
viewHeaderHintStyle: widget.headerHintStyle,
dividerColor: widget.dividerColor,
@ -474,6 +483,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
this.viewSurfaceTintColor,
this.viewSide,
this.viewShape,
this.viewHeaderHeight,
this.viewHeaderTextStyle,
this.viewHeaderHintStyle,
this.dividerColor,
@ -501,6 +511,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
final Color? viewSurfaceTintColor;
final BorderSide? viewSide;
final OutlinedBorder? viewShape;
final double? viewHeaderHeight;
final TextStyle? viewHeaderTextStyle;
final TextStyle? viewHeaderHintStyle;
final Color? dividerColor;
@ -644,6 +655,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> {
viewSurfaceTintColor: viewSurfaceTintColor,
viewSide: viewSide,
viewShape: viewShape,
viewHeaderHeight: viewHeaderHeight,
viewHeaderTextStyle: viewHeaderTextStyle,
viewHeaderHintStyle: viewHeaderHintStyle,
dividerColor: dividerColor,
@ -683,6 +695,7 @@ class _ViewContent extends StatefulWidget {
this.viewSurfaceTintColor,
this.viewSide,
this.viewShape,
this.viewHeaderHeight,
this.viewHeaderTextStyle,
this.viewHeaderHintStyle,
this.dividerColor,
@ -709,6 +722,7 @@ class _ViewContent extends StatefulWidget {
final Color? viewSurfaceTintColor;
final BorderSide? viewSide;
final OutlinedBorder? viewShape;
final double? viewHeaderHeight;
final TextStyle? viewHeaderTextStyle;
final TextStyle? viewHeaderHintStyle;
final Color? dividerColor;
@ -836,6 +850,10 @@ class _ViewContentState extends State<_ViewContent> {
?? viewTheme.dividerColor
?? dividerTheme.color
?? viewDefaults.dividerColor!;
final double? effectiveHeaderHeight = widget.viewHeaderHeight ?? viewTheme.headerHeight;
final BoxConstraints? headerConstraints = effectiveHeaderHeight == null
? null
: BoxConstraints.tightFor(height: effectiveHeaderHeight);
final TextStyle? effectiveTextStyle = widget.viewHeaderTextStyle
?? viewTheme.headerTextStyle
?? viewDefaults.headerTextStyle;
@ -885,7 +903,7 @@ class _ViewContentState extends State<_ViewContent> {
bottom: false,
child: SearchBar(
autoFocus: true,
constraints: widget.showFullScreenView ? BoxConstraints(minHeight: _SearchViewDefaultsM3.fullScreenBarHeight) : null,
constraints: headerConstraints ?? (widget.showFullScreenView ? BoxConstraints(minHeight: _SearchViewDefaultsM3.fullScreenBarHeight) : null),
leading: widget.viewLeading ?? defaultLeading,
trailing: widget.viewTrailing ?? defaultTrailing,
hintText: widget.viewHintText,
@ -956,6 +974,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
super.viewElevation,
super.viewSide,
super.viewShape,
double? viewHeaderHeight,
TextStyle? viewHeaderTextStyle,
TextStyle? viewHeaderHintStyle,
super.dividerColor,
@ -971,6 +990,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor {
super.keyboardType,
}) : super(
viewHintText: viewHintText ?? barHintText,
headerHeight: viewHeaderHeight,
headerTextStyle: viewHeaderTextStyle,
headerHintStyle: viewHeaderHintStyle,
viewOnSubmitted: onSubmitted,

View file

@ -42,6 +42,7 @@ class SearchViewThemeData with Diagnosticable {
this.constraints,
this.side,
this.shape,
this.headerHeight,
this.headerTextStyle,
this.headerHintStyle,
this.dividerColor,
@ -62,6 +63,9 @@ class SearchViewThemeData with Diagnosticable {
/// Overrides the default value of the [SearchAnchor.viewShape].
final OutlinedBorder? shape;
/// Overrides the default value of the [SearchAnchor.headerHeight].
final double? headerHeight;
/// Overrides the default value for [SearchAnchor.headerTextStyle].
final TextStyle? headerTextStyle;
@ -82,6 +86,7 @@ class SearchViewThemeData with Diagnosticable {
Color? surfaceTintColor,
BorderSide? side,
OutlinedBorder? shape,
double? headerHeight,
TextStyle? headerTextStyle,
TextStyle? headerHintStyle,
BoxConstraints? constraints,
@ -93,6 +98,7 @@ class SearchViewThemeData with Diagnosticable {
surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor,
side: side ?? this.side,
shape: shape ?? this.shape,
headerHeight: headerHeight ?? this.headerHeight,
headerTextStyle: headerTextStyle ?? this.headerTextStyle,
headerHintStyle: headerHintStyle ?? this.headerHintStyle,
constraints: constraints ?? this.constraints,
@ -111,6 +117,7 @@ class SearchViewThemeData with Diagnosticable {
surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t),
side: _lerpSides(a?.side, b?.side, t),
shape: OutlinedBorder.lerp(a?.shape, b?.shape, t),
headerHeight: lerpDouble(a?.headerHeight, b?.headerHeight, t),
headerTextStyle: TextStyle.lerp(a?.headerTextStyle, b?.headerTextStyle, t),
headerHintStyle: TextStyle.lerp(a?.headerTextStyle, b?.headerTextStyle, t),
constraints: BoxConstraints.lerp(a?.constraints, b?.constraints, t),
@ -125,6 +132,7 @@ class SearchViewThemeData with Diagnosticable {
surfaceTintColor,
side,
shape,
headerHeight,
headerTextStyle,
headerHintStyle,
constraints,
@ -145,6 +153,7 @@ class SearchViewThemeData with Diagnosticable {
&& other.surfaceTintColor == surfaceTintColor
&& other.side == side
&& other.shape == shape
&& other.headerHeight == headerHeight
&& other.headerTextStyle == headerTextStyle
&& other.headerHintStyle == headerHintStyle
&& other.constraints == constraints
@ -159,6 +168,7 @@ class SearchViewThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<Color?>('surfaceTintColor', surfaceTintColor, defaultValue: null));
properties.add(DiagnosticsProperty<BorderSide?>('side', side, defaultValue: null));
properties.add(DiagnosticsProperty<OutlinedBorder?>('shape', shape, defaultValue: null));
properties.add(DiagnosticsProperty<double?>('headerHeight', headerHeight, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle?>('headerTextStyle', headerTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle?>('headerHintStyle', headerHintStyle, defaultValue: null));
properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: null));

View file

@ -3016,6 +3016,52 @@ void main() {
final Opacity opacityWidget = tester.widget<Opacity>(opacityFinder);
expect(opacityWidget.opacity, 0.38);
});
testWidgets('SearchAnchor respects headerHeight', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Center(
child: Material(
child: SearchAnchor(
isFullScreen: true,
builder: (BuildContext context, SearchController controller) {
return const Icon(Icons.search);
},
headerHeight: 32,
suggestionsBuilder: (BuildContext context, SearchController controller) {
return <Widget>[];
},
),
),
),
));
await tester.pump();
await tester.tap(find.byIcon(Icons.search)); // Open search view.
await tester.pumpAndSettle();
final Finder findHeader = find.descendant(of: findViewContent(), matching: find.byType(SearchBar));
expect(tester.getSize(findHeader).height, 32);
});
testWidgets('SearchAnchor.bar respects viewHeaderHeight', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Center(
child: Material(
child: SearchAnchor.bar(
isFullScreen: true,
viewHeaderHeight: 32,
suggestionsBuilder: (BuildContext context, SearchController controller) {
return <Widget>[];
},
),
),
),
));
await tester.pump();
await tester.tap(find.byType(SearchBar)); // Open search view.
await tester.pumpAndSettle();
final Finder findHeader = find.descendant(of: findViewContent(), matching: find.byType(SearchBar));
final RenderBox box = tester.renderObject(findHeader);
expect(box.size.height, 32);
});
}
Future<void> checkSearchBarDefaults(WidgetTester tester, ColorScheme colorScheme, Material material) async {

View file

@ -28,6 +28,7 @@ void main() {
expect(themeData.constraints, null);
expect(themeData.side, null);
expect(themeData.shape, null);
expect(themeData.headerHeight, null);
expect(themeData.headerTextStyle, null);
expect(themeData.headerHintStyle, null);
expect(themeData.dividerColor, null);
@ -39,6 +40,7 @@ void main() {
expect(theme.data.constraints, null);
expect(theme.data.side, null);
expect(theme.data.shape, null);
expect(theme.data.headerHeight, null);
expect(theme.data.headerTextStyle, null);
expect(theme.data.headerHintStyle, null);
expect(theme.data.dividerColor, null);
@ -65,6 +67,7 @@ void main() {
surfaceTintColor: Color(0xfffffff3),
side: BorderSide(width: 2.5, color: Color(0xfffffff5)),
shape: RoundedRectangleBorder(),
headerHeight: 35.5,
headerTextStyle: TextStyle(fontSize: 24.0),
headerHintStyle: TextStyle(fontSize: 16.0),
constraints: BoxConstraints(minWidth: 350, minHeight: 240),
@ -80,9 +83,10 @@ void main() {
expect(description[2], 'surfaceTintColor: Color(0xfffffff3)');
expect(description[3], 'side: BorderSide(color: Color(0xfffffff5), width: 2.5)');
expect(description[4], 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)');
expect(description[5], 'headerTextStyle: TextStyle(inherit: true, size: 24.0)');
expect(description[6], 'headerHintStyle: TextStyle(inherit: true, size: 16.0)');
expect(description[7], 'constraints: BoxConstraints(350.0<=w<=Infinity, 240.0<=h<=Infinity)');
expect(description[5], 'headerHeight: 35.5');
expect(description[6], 'headerTextStyle: TextStyle(inherit: true, size: 24.0)');
expect(description[7], 'headerHintStyle: TextStyle(inherit: true, size: 16.0)');
expect(description[8], 'constraints: BoxConstraints(350.0<=w<=Infinity, 240.0<=h<=Infinity)');
});
group('[Theme, SearchViewTheme, SearchView properties overrides]', () {
@ -91,6 +95,7 @@ void main() {
const Color surfaceTintColor = Color(0xff000002);
const BorderSide side = BorderSide(color: Color(0xff000003), width: 2.0);
const OutlinedBorder shape = RoundedRectangleBorder(side: side, borderRadius: BorderRadius.all(Radius.circular(20.0)));
const double headerHeight = 45.0;
const TextStyle headerTextStyle = TextStyle(color: Color(0xff000004), fontSize: 20.0);
const TextStyle headerHintStyle = TextStyle(color: Color(0xff000005), fontSize: 18.0);
const BoxConstraints constraints = BoxConstraints(minWidth: 250.0, maxWidth: 300.0, minHeight: 450.0);
@ -101,6 +106,7 @@ void main() {
surfaceTintColor: surfaceTintColor,
side: side,
shape: shape,
headerHeight: headerHeight,
headerTextStyle: headerTextStyle,
headerHintStyle: headerHintStyle,
constraints: constraints,
@ -139,6 +145,7 @@ void main() {
viewSurfaceTintColor: surfaceTintColor,
viewSide: side,
viewShape: shape,
headerHeight: headerHeight,
headerTextStyle: headerTextStyle,
headerHintStyle: headerHintStyle,
viewConstraints: constraints,
@ -189,6 +196,8 @@ void main() {
expect(hintText.style?.color, headerHintStyle.color);
expect(hintText.style?.fontSize, headerHintStyle.fontSize);
final RenderBox box = tester.renderObject(find.descendant(of: findViewContent(), matching: find.byType(SearchBar)));
expect(box.size.height, headerHeight);
await tester.enterText(find.byType(TextField), 'input');
final EditableText inputText = tester.widget(find.text('input'));
expect(inputText.style.color, headerTextStyle.color);