Unverified Commit cd4fe85b authored by Hans Muller's avatar Hans Muller Committed by GitHub

Added support for AppBarTheme.toolbarHeight (#80467)

parent 2f1d0340
......@@ -54,6 +54,14 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
toolbarHeight != oldDelegate.toolbarHeight;
}
class _PreferredAppBarSize extends Size {
_PreferredAppBarSize(this.toolbarHeight, this.bottomHeight)
: super.fromHeight((toolbarHeight ?? kToolbarHeight) + (bottomHeight ?? 0));
final double? toolbarHeight;
final double? bottomHeight;
}
/// A material design app bar.
///
/// An app bar consists of a toolbar and potentially other widgets, such as a
......@@ -202,9 +210,21 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
assert(primary != null),
assert(toolbarOpacity != null),
assert(bottomOpacity != null),
preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize.height ?? 0.0)),
preferredSize = _PreferredAppBarSize(toolbarHeight, bottom?.preferredSize.height),
super(key: key);
/// Used by [Scaffold] to compute its [AppBar]'s overall height. The returned value is
/// the same `preferredSize.height` unless [AppBar.toolbarHeight] was null and
/// `AppBarTheme.of(context).toolbarHeight` is non-null. In that case the
/// return value is the sum of the theme's toolbar height and the height of
/// the app bar's [AppBar.bottom] widget.
static double preferredHeightFor(BuildContext context, Size preferredSize) {
if (preferredSize is _PreferredAppBarSize && preferredSize.toolbarHeight == null) {
return (AppBarTheme.of(context).toolbarHeight ?? kToolbarHeight) + (preferredSize.bottomHeight ?? 0);
}
return preferredSize.height;
}
/// {@template flutter.material.appbar.leading}
/// A widget to display before the toolbar's [title].
///
......@@ -781,7 +801,7 @@ class _AppBarState extends State<AppBar> {
final bool canPop = parentRoute?.canPop ?? false;
final bool useCloseButton = parentRoute is PageRoute<dynamic> && parentRoute.fullscreenDialog;
final double toolbarHeight = widget.toolbarHeight ?? kToolbarHeight;
final double toolbarHeight = widget.toolbarHeight ?? appBarTheme.toolbarHeight ?? kToolbarHeight;
final bool backwardsCompatibility = widget.backwardsCompatibility ?? appBarTheme.backwardsCompatibility ?? true;
final Color backgroundColor = backwardsCompatibility
......
......@@ -39,6 +39,7 @@ class AppBarTheme with Diagnosticable {
this.textTheme,
this.centerTitle,
this.titleSpacing,
this.toolbarHeight,
this.toolbarTextStyle,
this.titleTextStyle,
this.systemOverlayStyle,
......@@ -144,6 +145,15 @@ class AppBarTheme with Diagnosticable {
/// If null, [AppBar] uses default value of [NavigationToolbar.kMiddleSpacing].
final double? titleSpacing;
/// Overrides the default value for the [AppBar.toolbarHeight]
/// property in all descendant [AppBar] widgets.
///
/// See also:
///
/// * [AppBar.preferredHeightFor], which computes the overall
/// height of an AppBar widget, taking this value into account.
final double? toolbarHeight;
/// Overrides the default value for the obsolete [AppBar.toolbarTextStyle]
/// property in all descendant [AppBar] widgets.
///
......@@ -184,6 +194,7 @@ class AppBarTheme with Diagnosticable {
TextTheme? textTheme,
bool? centerTitle,
double? titleSpacing,
double? toolbarHeight,
TextStyle? toolbarTextStyle,
TextStyle? titleTextStyle,
SystemUiOverlayStyle? systemOverlayStyle,
......@@ -204,6 +215,7 @@ class AppBarTheme with Diagnosticable {
textTheme: textTheme ?? this.textTheme,
centerTitle: centerTitle ?? this.centerTitle,
titleSpacing: titleSpacing ?? this.titleSpacing,
toolbarHeight: toolbarHeight ?? this.toolbarHeight,
toolbarTextStyle: toolbarTextStyle ?? this.toolbarTextStyle,
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
systemOverlayStyle: systemOverlayStyle ?? this.systemOverlayStyle,
......@@ -234,6 +246,7 @@ class AppBarTheme with Diagnosticable {
textTheme: TextTheme.lerp(a?.textTheme, b?.textTheme, t),
centerTitle: t < 0.5 ? a?.centerTitle : b?.centerTitle,
titleSpacing: lerpDouble(a?.titleSpacing, b?.titleSpacing, t),
toolbarHeight: lerpDouble(a?.toolbarHeight, b?.toolbarHeight, t),
toolbarTextStyle: TextStyle.lerp(a?.toolbarTextStyle, b?.toolbarTextStyle, t),
titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t),
systemOverlayStyle: t < 0.5 ? a?.systemOverlayStyle : b?.systemOverlayStyle,
......@@ -254,6 +267,7 @@ class AppBarTheme with Diagnosticable {
textTheme,
centerTitle,
titleSpacing,
toolbarHeight,
toolbarTextStyle,
titleTextStyle,
systemOverlayStyle,
......@@ -278,6 +292,7 @@ class AppBarTheme with Diagnosticable {
&& other.textTheme == textTheme
&& other.centerTitle == centerTitle
&& other.titleSpacing == titleSpacing
&& other.toolbarHeight == toolbarHeight
&& other.toolbarTextStyle == toolbarTextStyle
&& other.titleTextStyle == titleTextStyle
&& other.systemOverlayStyle == systemOverlayStyle
......@@ -297,6 +312,7 @@ class AppBarTheme with Diagnosticable {
properties.add(DiagnosticsProperty<TextTheme>('textTheme', textTheme, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('centerTitle', centerTitle, defaultValue: null));
properties.add(DiagnosticsProperty<double>('titleSpacing', titleSpacing, defaultValue: null));
properties.add(DiagnosticsProperty<double>('toolbarHeight', toolbarHeight, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('toolbarTextStyle', toolbarTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('backwardsCompatibility', backwardsCompatibility, defaultValue: null));
......
......@@ -3035,7 +3035,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
if (widget.appBar != null) {
final double topPadding = widget.primary ? mediaQuery.padding.top : 0.0;
_appBarMaxHeight = widget.appBar!.preferredSize.height + topPadding;
_appBarMaxHeight = AppBar.preferredHeightFor(context, widget.appBar!.preferredSize) + topPadding;
assert(_appBarMaxHeight! >= 0.0 && _appBarMaxHeight!.isFinite);
_addIfNonNull(
children,
......
......@@ -2822,4 +2822,57 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('AppBar.preferredHeightFor', (WidgetTester tester) async {
late double preferredHeight;
late Size preferredSize;
Widget buildFrame({ double? themeToolbarHeight, double? appBarToolbarHeight }) {
final AppBar appBar = AppBar(
toolbarHeight: appBarToolbarHeight,
);
return MaterialApp(
theme: ThemeData.light().copyWith(
appBarTheme: AppBarTheme(
toolbarHeight: themeToolbarHeight,
),
),
home: Builder(
builder: (BuildContext context) {
preferredHeight = AppBar.preferredHeightFor(context, appBar.preferredSize);
preferredSize = appBar.preferredSize;
return Scaffold(
appBar: appBar,
body: const Placeholder(),
);
},
),
);
}
await tester.pumpWidget(buildFrame());
expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight);
expect(preferredHeight, kToolbarHeight);
expect(preferredSize.height, kToolbarHeight);
await tester.pumpWidget(buildFrame(themeToolbarHeight: 96));
await tester.pumpAndSettle(); // Animate MaterialApp theme change.
expect(tester.getSize(find.byType(AppBar)).height, 96);
expect(preferredHeight, 96);
// Special case: AppBarTheme.toolbarHeight specified,
// AppBar.theme.toolbarHeight is null.
expect(preferredSize.height, kToolbarHeight);
await tester.pumpWidget(buildFrame(appBarToolbarHeight: 64));
await tester.pumpAndSettle(); // Animate MaterialApp theme change.
expect(tester.getSize(find.byType(AppBar)).height, 64);
expect(preferredHeight, 64);
expect(preferredSize.height, 64);
await tester.pumpWidget(buildFrame(appBarToolbarHeight: 64, themeToolbarHeight: 96));
await tester.pumpAndSettle(); // Animate MaterialApp theme change.
expect(tester.getSize(find.byType(AppBar)).height, 64);
expect(preferredHeight, 64);
expect(preferredSize.height, 64);
});
}
......@@ -15,14 +15,18 @@ void main() {
});
testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Scaffold(appBar: AppBar(
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(
backwardsCompatibility: false,
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { }),
],
)),
));
),
),
),
);
final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester);
......@@ -38,21 +42,27 @@ void main() {
expect(actionsIconTheme.data, const IconThemeData(color: Colors.white));
expect(actionIconText.text.style!.color, Colors.white);
expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().white.bodyText2));
expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight);
expect(tester.getSize(find.byType(AppBar)).width, 800);
});
testWidgets('AppBar uses values from AppBarTheme', (WidgetTester tester) async {
final AppBarTheme appBarTheme = _appBarTheme();
await tester.pumpWidget(MaterialApp(
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(appBarTheme: appBarTheme),
home: Scaffold(appBar: AppBar(
home: Scaffold(
appBar: AppBar(
backwardsCompatibility: false,
title: const Text('App Bar Title'),
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { }),
],
)),
));
),
),
),
);
final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester);
......@@ -68,6 +78,8 @@ void main() {
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color);
expect(text.style, appBarTheme.toolbarTextStyle);
expect(tester.getSize(find.byType(AppBar)).height, appBarTheme.toolbarHeight);
expect(tester.getSize(find.byType(AppBar)).width, 800);
});
testWidgets('SliverAppBar allows AppBar to determine backwardsCompatibility', (WidgetTester tester) async {
......@@ -531,6 +543,7 @@ AppBarTheme _appBarTheme() {
elevation: elevation,
shadowColor: shadowColor,
iconTheme: iconThemeData,
toolbarHeight: 96,
toolbarTextStyle: TextStyle(color: Colors.yellow),
titleTextStyle: TextStyle(color: Colors.pink),
);
......
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