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

Update AppBar and AppBar Theme to new Theme conventions and latest Material spec (#71184)

parent 8f3a12f1
...@@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart'; ...@@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart';
import 'app_bar_theme.dart'; import 'app_bar_theme.dart';
import 'back_button.dart'; import 'back_button.dart';
import 'color_scheme.dart';
import 'constants.dart'; import 'constants.dart';
import 'debug.dart'; import 'debug.dart';
import 'flexible_space_bar.dart'; import 'flexible_space_bar.dart';
...@@ -52,12 +53,6 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate { ...@@ -52,12 +53,6 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
toolbarHeight != oldDelegate.toolbarHeight; toolbarHeight != oldDelegate.toolbarHeight;
} }
// TODO(eseidel): Toolbar needs to change size based on orientation:
// https://material.io/design/components/app-bars-top.html#specs
// Mobile Landscape: 48dp
// Mobile Portrait: 56dp
// Tablet/Desktop: 64dp
/// A material design app bar. /// A material design app bar.
/// ///
/// An app bar consists of a toolbar and potentially other widgets, such as a /// An app bar consists of a toolbar and potentially other widgets, such as a
...@@ -101,33 +96,9 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate { ...@@ -101,33 +96,9 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
/// This sample shows an [AppBar] with two simple actions. The first action /// This sample shows an [AppBar] with two simple actions. The first action
/// opens a [SnackBar], while the second action navigates to a new page. /// opens a [SnackBar], while the second action navigates to a new page.
/// ///
/// ```dart preamble
/// final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
/// final SnackBar snackBar = const SnackBar(content: Text('Showing Snackbar'));
///
/// void openPage(BuildContext context) {
/// Navigator.push(context, MaterialPageRoute(
/// builder: (BuildContext context) {
/// return Scaffold(
/// appBar: AppBar(
/// title: const Text('Next page'),
/// ),
/// body: const Center(
/// child: Text(
/// 'This is the next page',
/// style: TextStyle(fontSize: 24),
/// ),
/// ),
/// );
/// },
/// ));
/// }
/// ```
///
/// ```dart /// ```dart
/// Widget build(BuildContext context) { /// Widget build(BuildContext context) {
/// return Scaffold( /// return Scaffold(
/// key: scaffoldKey,
/// appBar: AppBar( /// appBar: AppBar(
/// title: const Text('AppBar Demo'), /// title: const Text('AppBar Demo'),
/// actions: <Widget>[ /// actions: <Widget>[
...@@ -135,14 +106,30 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate { ...@@ -135,14 +106,30 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
/// icon: const Icon(Icons.add_alert), /// icon: const Icon(Icons.add_alert),
/// tooltip: 'Show Snackbar', /// tooltip: 'Show Snackbar',
/// onPressed: () { /// onPressed: () {
/// ScaffoldMessenger.of(context).showSnackBar(snackBar); /// ScaffoldMessenger.of(context).showSnackBar(
/// const SnackBar(content: Text('This is a snackbar'))
/// );
/// }, /// },
/// ), /// ),
/// IconButton( /// IconButton(
/// icon: const Icon(Icons.navigate_next), /// icon: const Icon(Icons.navigate_next),
/// tooltip: 'Next page', /// tooltip: 'Go to the next page',
/// onPressed: () { /// onPressed: () {
/// openPage(context); /// Navigator.push(context, MaterialPageRoute(
/// builder: (BuildContext context) {
/// return Scaffold(
/// appBar: AppBar(
/// title: const Text('Next page'),
/// ),
/// body: const Center(
/// child: Text(
/// 'This is the next page',
/// style: TextStyle(fontSize: 24),
/// ),
/// ),
/// );
/// },
/// ));
/// }, /// },
/// ), /// ),
/// ], /// ],
...@@ -174,14 +161,10 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate { ...@@ -174,14 +161,10 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
class AppBar extends StatefulWidget implements PreferredSizeWidget { class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// Creates a material design app bar. /// Creates a material design app bar.
/// ///
/// The arguments [primary], [toolbarOpacity], [bottomOpacity] /// The arguments [primary], [toolbarOpacity], [bottomOpacity],
/// and [automaticallyImplyLeading] must not be null. Additionally, if /// [backwardsCompatibility], and [automaticallyImplyLeading] must
/// [elevation] is specified, it must be non-negative. /// not be null. Additionally, if [elevation] is specified, it must
/// /// be non-negative.
/// If [backgroundColor], [elevation], [shadowColor], [brightness], [iconTheme],
/// [actionsIconTheme], [textTheme] or [centerTitle] are null, then their
/// [AppBarTheme] values will be used. If the corresponding [AppBarTheme] property is null,
/// then the default specified in the property's documentation will be used.
/// ///
/// Typically used in the [Scaffold.appBar] property. /// Typically used in the [Scaffold.appBar] property.
AppBar({ AppBar({
...@@ -196,6 +179,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -196,6 +179,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
this.shadowColor, this.shadowColor,
this.shape, this.shape,
this.backgroundColor, this.backgroundColor,
this.foregroundColor,
this.brightness, this.brightness,
this.iconTheme, this.iconTheme,
this.actionsIconTheme, this.actionsIconTheme,
...@@ -208,15 +192,21 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -208,15 +192,21 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
this.bottomOpacity = 1.0, this.bottomOpacity = 1.0,
this.toolbarHeight, this.toolbarHeight,
this.leadingWidth, this.leadingWidth,
this.backwardsCompatibility = true,
this.toolbarTextStyle,
this.titleTextStyle,
this.systemOverlayStyle,
}) : assert(automaticallyImplyLeading != null), }) : assert(automaticallyImplyLeading != null),
assert(elevation == null || elevation >= 0.0), assert(elevation == null || elevation >= 0.0),
assert(primary != null), assert(primary != null),
assert(toolbarOpacity != null), assert(toolbarOpacity != null),
assert(bottomOpacity != null), assert(bottomOpacity != null),
assert(backwardsCompatibility != null),
preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize.height ?? 0.0)), preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize.height ?? 0.0)),
super(key: key); super(key: key);
/// A widget to display before the [title]. /// {@template flutter.material.appbar.leading}
/// A widget to display before the toolbar's [title].
/// ///
/// Typically the [leading] widget is an [Icon] or an [IconButton]. /// Typically the [leading] widget is an [Icon] or an [IconButton].
/// ///
...@@ -230,6 +220,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -230,6 +220,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// widget with an [IconButton] that opens the drawer (using [Icons.menu]). If /// widget with an [IconButton] that opens the drawer (using [Icons.menu]). If
/// there's no [Drawer] and the parent [Navigator] can go back, the [AppBar] /// there's no [Drawer] and the parent [Navigator] can go back, the [AppBar]
/// will use a [BackButton] that calls [Navigator.maybePop]. /// will use a [BackButton] that calls [Navigator.maybePop].
/// {@endtemplate}
/// ///
/// {@tool snippet} /// {@tool snippet}
/// ///
...@@ -263,19 +254,24 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -263,19 +254,24 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// * [Scaffold.drawer], in which the [Drawer] is usually placed. /// * [Scaffold.drawer], in which the [Drawer] is usually placed.
final Widget? leading; final Widget? leading;
/// {@template flutter.material.appbar.automaticallyImplyLeading}
/// Controls whether we should try to imply the leading widget if null. /// Controls whether we should try to imply the leading widget if null.
/// ///
/// If true and [leading] is null, automatically try to deduce what the leading /// If true and [leading] is null, automatically try to deduce what the leading
/// widget should be. If false and [leading] is null, leading space is given to [title]. /// widget should be. If false and [leading] is null, leading space is given to [title].
/// If leading widget is not null, this parameter has no effect. /// If leading widget is not null, this parameter has no effect.
/// {@endtemplate}
final bool automaticallyImplyLeading; final bool automaticallyImplyLeading;
/// {@template flutter.material.appbar.title}
/// The primary widget displayed in the app bar. /// The primary widget displayed in the app bar.
/// ///
/// Becomes the middle component of the [NavigationToolbar] built by this widget.
//.
/// Typically a [Text] widget that contains a description of the current /// Typically a [Text] widget that contains a description of the current
/// contents of the app. /// contents of the app.
/// {@endtemplate}
/// ///
/// Becomes the middle component of the [NavigationToolbar] built by this widget.
/// The [title]'s width is constrained to fit within the remaining space /// The [title]'s width is constrained to fit within the remaining space
/// between the toolbar's [leading] and [actions] widgets. Its height is /// between the toolbar's [leading] and [actions] widgets. Its height is
/// _not_ constrained. The [title] is vertically centered and clipped to fit /// _not_ constrained. The [title] is vertically centered and clipped to fit
...@@ -302,7 +298,8 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -302,7 +298,8 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// ``` /// ```
final Widget? title; final Widget? title;
/// Widgets to display in a row after the [title] widget. /// {@template flutter.material.appbar.actions}
/// A list of Widgets to display in a row after the [title] widget.
/// ///
/// Typically these widgets are [IconButton]s representing common operations. /// Typically these widgets are [IconButton]s representing common operations.
/// For less common operations, consider using a [PopupMenuButton] as the /// For less common operations, consider using a [PopupMenuButton] as the
...@@ -311,8 +308,36 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -311,8 +308,36 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// The [actions] become the trailing component of the [NavigationToolbar] built /// The [actions] become the trailing component of the [NavigationToolbar] built
/// by this widget. The height of each action is constrained to be no bigger /// by this widget. The height of each action is constrained to be no bigger
/// than the [toolbarHeight]. /// than the [toolbarHeight].
/// {@endtemplate}
///
/// {@tool snippet}
///
/// ```dart
/// Scaffold(
/// body: CustomScrollView(
/// primary: true,
/// slivers: <Widget>[
/// SliverAppBar(
/// title: Text('Hello World'),
/// actions: <Widget>[
/// IconButton(
/// icon: Icon(Icons.shopping_cart),
/// tooltip: 'Open shopping cart',
/// onPressed: () {
/// // handle the press
/// },
/// ),
/// ],
/// ),
/// // ...rest of body...
/// ],
/// ),
/// )
/// ```
/// {@end-tool}
final List<Widget>? actions; final List<Widget>? actions;
/// {@template flutter.material.appbar.flexibleSpace}
/// This widget is stacked behind the toolbar and the tab bar. Its height will /// This widget is stacked behind the toolbar and the tab bar. Its height will
/// be the same as the app bar's overall height. /// be the same as the app bar's overall height.
/// ///
...@@ -321,110 +346,220 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -321,110 +346,220 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// changes the [AppBar]'s height when scrolled. /// changes the [AppBar]'s height when scrolled.
/// ///
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details. /// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
/// {@endtemplate}
final Widget? flexibleSpace; final Widget? flexibleSpace;
/// {@template flutter.material.appbar.bottom}
/// This widget appears across the bottom of the app bar. /// This widget appears across the bottom of the app bar.
/// ///
/// Typically a [TabBar]. Only widgets that implement [PreferredSizeWidget] can /// Typically a [TabBar]. Only widgets that implement [PreferredSizeWidget] can
/// be used at the bottom of an app bar. /// be used at the bottom of an app bar.
/// {@endtemplate}
/// ///
/// See also: /// See also:
/// ///
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size. /// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
final PreferredSizeWidget? bottom; final PreferredSizeWidget? bottom;
/// {@template flutter.material.appbar.elevation}
/// The z-coordinate at which to place this app bar relative to its parent. /// The z-coordinate at which to place this app bar relative to its parent.
/// ///
/// This controls the size of the shadow below the app bar. /// This property controls the size of the shadow below the app bar.
/// ///
/// The value is non-negative. /// The value must be non-negative.
/// ///
/// If this property is null, then [AppBarTheme.elevation] of /// If this property is null, then [AppBarTheme.elevation] of
/// [ThemeData.appBarTheme] is used. If that is also null, the default value /// [ThemeData.appBarTheme] is used. If that is also null, the
/// is 4. /// default value is 4.
/// {@endtemplate}
///
/// See also:
///
/// * [shadowColor], which is the color of the shadow below the app bar.
/// * [shape], which defines the shape of the app bar's [Material] and its
/// shadow.
final double? elevation; final double? elevation;
/// The color to paint the shadow below the app bar. /// {@template flutter.material.appbar.shadowColor}
/// The of the shadow below the app bar.
/// ///
/// If this property is null, then [AppBarTheme.shadowColor] of /// If this property is null, then [AppBarTheme.shadowColor] of
/// [ThemeData.appBarTheme] is used. If that is also null, the default value /// [ThemeData.appBarTheme] is used. If that is also null, the default value
/// is fully opaque black. /// is fully opaque black.
/// {@endtemplate}
///
/// See also:
///
/// * [elevation], which defines the size of the shadow below the app bar.
/// * [shape], which defines the shape of the app bar and its shadow.
final Color? shadowColor; final Color? shadowColor;
/// The material's shape as well its shadow. /// {@template flutter.material.appbar.shape}
/// The shape of the app bar's material's shape as well as its shadow.
/// ///
/// A shadow is only displayed if the [elevation] is greater than /// A shadow is only displayed if the [elevation] is greater than
/// zero. /// zero.
/// {@endtemplate}
///
/// See also:
///
/// * [elevation], which defines the size of the shadow below the app bar.
/// * [shadowColor], which is the color of the shadow below the app bar.
final ShapeBorder? shape; final ShapeBorder? shape;
/// The color to use for the app bar's material. Typically this should be set /// {@template flutter.material.appbar.backgroundColor}
/// along with [brightness], [iconTheme], [textTheme]. /// The fill color to use for an app bar's [Material].
/// ///
/// If this property is null, then [AppBarTheme.color] of /// If null, then the [AppBarTheme.backgroundColor] is used. If that value is also
/// [ThemeData.appBarTheme] is used. If that is also null, then /// null, then [AppBar] uses the overall theme's [ColorScheme.primary] if the
/// [ThemeData.primaryColor] is used. /// overall theme's brightness is [Brightness.light], and [ColorScheme.surface]
/// if the overall theme's [brightness] is [Brightness.dark].
/// {@endtemplate}
///
/// See also:
///
/// * [foregroundColor], which specifies the color for icons and text within
/// the app bar.
/// * [Theme.of], which returns the current overall Material theme as
/// a [ThemeData].
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
/// default colors are based on.
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
/// is light or dark.
final Color? backgroundColor; final Color? backgroundColor;
/// The brightness of the app bar's material. Typically this is set along /// {@template flutter.material.appbar.foregroundColor}
/// with [backgroundColor], [iconTheme], [textTheme]. /// The default color for [Text] and [Icon]s within the app bar.
/// ///
/// If this property is null, then [AppBarTheme.brightness] of /// If null, then [AppBarTheme.foregroundColor] is used. If that
/// [ThemeData.appBarTheme] is used. If that is also null, then /// value is also null, then [AppBar] uses the overall theme's
/// [ThemeData.primaryColorBrightness] is used. /// [ColorScheme.onPrimary] if the overall theme's brightness is
/// [Brightness.light], and [ColorScheme.onSurface] if the overall
/// theme's [brightness] is [Brightness.dark].
///
/// This color is used to configure [DefaultTextStyle] that contains
/// the toolbar's children, and the default [IconTheme] widgets that
/// are created if [iconTheme] and [actionsIconTheme] are null.
/// {@endtemplate}
///
/// See also:
///
/// * [backgroundColor], which specifies the app bar's background color.
/// * [Theme.of], which returns the current overall Material theme as
/// a [ThemeData].
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
/// default colors are based on.
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
/// is light or dark.
final Color? foregroundColor;
/// {@template flutter.material.appbar.brightness}
/// This property is obsolete, please use [systemOverlayStyle] instead.
///
/// Determines the brightness of the [SystemUiOverlayStyle]: for
/// [Brightness.dark], [SystemUiOverlayStyle.light] is used and fo
/// [Brightness.light], [SystemUiOverlayStyle.dark] is used.
///
/// If this value is null then [AppBarTheme.brightness] is used
/// and if that's null then overall theme's brightness is used.
///
/// The AppBar is built within a `AnnotatedRegion<SystemUiOverlayStyle>`
/// which causes [SystemChrome.setSystemUIOverlayStyle] to be called
/// automatically. Apps should not enclose the AppBar with
/// their own [AnnotatedRegion].
/// {@endtemplate}
///
/// See also:
///
/// * [Theme.of], which returns the current overall Material theme as
/// a [ThemeData].
/// * [ThemeData.colorScheme], the thirteen colors that most Material widget
/// default colors are based on.
/// * [ColorScheme.brightness], which indicates if the overall [Theme]
/// is light or dark.
/// * [backwardsCompatibility], which forces AppBar to use this
/// obsolete property.
final Brightness? brightness; final Brightness? brightness;
/// The color, opacity, and size to use for app bar icons. Typically this /// {@template flutter.material.appbar.iconTheme}
/// is set along with [backgroundColor], [brightness], [textTheme]. /// The color, opacity, and size to use for toolbar icons.
/// ///
/// If this property is null, then [AppBarTheme.iconTheme] of /// If this property is null, then a copy of [ThemeData.iconTheme]
/// [ThemeData.appBarTheme] is used. If that is also null, then /// is used, with the [IconThemeData.color] set to the
/// [ThemeData.primaryIconTheme] is used. /// app bar's [foregroundColor].
/// {@endtemplate}
///
/// See also:
///
/// * [actionsIconTheme], which defines the appearance of icons in
/// in the [actions] list.
final IconThemeData? iconTheme; final IconThemeData? iconTheme;
/// {@template flutter.material.appbar.actionsIconTheme}
/// The color, opacity, and size to use for the icons that appear in the app /// The color, opacity, and size to use for the icons that appear in the app
/// bar's [actions]. This should only be used when the [actions] should be /// bar's [actions].
///
/// This property should only be used when the [actions] should be
/// themed differently than the icon that appears in the app bar's [leading] /// themed differently than the icon that appears in the app bar's [leading]
/// widget. /// widget.
/// ///
/// If this property is null, then [AppBarTheme.actionsIconTheme] of /// If this property is null, then [AppBarTheme.actionsIconTheme] of
/// [ThemeData.appBarTheme] is used. If that is also null, then this falls /// [ThemeData.appBarTheme] is used. If that is also null, then the value of
/// back to [iconTheme]. /// [iconTheme] is used.
/// {@endtemplate}
///
/// See also:
///
/// * [iconTheme], which defines the appearance of all of the toolbar icons.
final IconThemeData? actionsIconTheme; final IconThemeData? actionsIconTheme;
/// {@template flutter.material.appbar.textTheme}
/// The typographic styles to use for text in the app bar. Typically this is /// The typographic styles to use for text in the app bar. Typically this is
/// set along with [brightness] [backgroundColor], [iconTheme]. /// set along with [brightness] [backgroundColor], [iconTheme].
/// ///
/// If this property is null, then [AppBarTheme.textTheme] of /// If this property is null, then [AppBarTheme.textTheme] of
/// [ThemeData.appBarTheme] is used. If that is also null, then /// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryTextTheme] is used. /// [ThemeData.primaryTextTheme] is used.
/// {@endtemplate}
final TextTheme? textTheme; final TextTheme? textTheme;
/// {@template flutter.material.appbar.primary}
/// Whether this app bar is being displayed at the top of the screen. /// Whether this app bar is being displayed at the top of the screen.
/// ///
/// If true, the app bar's toolbar elements and [bottom] widget will be /// If true, the app bar's toolbar elements and [bottom] widget will be
/// padded on top by the height of the system status bar. The layout /// padded on top by the height of the system status bar. The layout
/// of the [flexibleSpace] is not affected by the [primary] property. /// of the [flexibleSpace] is not affected by the [primary] property.
/// {@endtemplate}
final bool primary; final bool primary;
/// {@template flutter.material.appbar.centerTitle}
/// Whether the title should be centered. /// Whether the title should be centered.
/// ///
/// If this property is null, then [AppBarTheme.centerTitle] of /// If this property is null, then [AppBarTheme.centerTitle] of
/// [ThemeData.appBarTheme] is used. If that is also null, then value is /// [ThemeData.appBarTheme] is used. If that is also null, then value is
/// adapted to the current [TargetPlatform]. /// adapted to the current [TargetPlatform].
/// {@endtemplate}
final bool? centerTitle; final bool? centerTitle;
/// {@template flutter.material.appbar.excludeHeaderSemantics}
/// Whether the title should be wrapped with header [Semantics]. /// Whether the title should be wrapped with header [Semantics].
/// ///
/// Defaults to false. /// Defaults to false.
/// {@endtemplate}
final bool excludeHeaderSemantics; final bool excludeHeaderSemantics;
/// {@template flutter.material.appbar.titleSpacing}
/// The spacing around [title] content on the horizontal axis. This spacing is /// The spacing around [title] content on the horizontal axis. This spacing is
/// applied even if there is no [leading] content or [actions]. If you want /// applied even if there is no [leading] content or [actions]. If you want
/// [title] to take all the space available, set this value to 0.0. /// [title] to take all the space available, set this value to 0.0.
/// ///
/// Defaults to [NavigationToolbar.kMiddleSpacing]. /// If this property is null, then [AppBarTheme.titleSpacing] of
/// [ThemeData.appBarTheme] is used. If that is also null, then the
/// default value is [NavigationToolbar.kMiddleSpacing].
/// {@endtemplate}
final double? titleSpacing; final double? titleSpacing;
/// {@template flutter.material.appbar.toolbarOpacity}
/// How opaque the toolbar part of the app bar is. /// How opaque the toolbar part of the app bar is.
/// ///
/// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent. /// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent.
...@@ -432,8 +567,10 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -432,8 +567,10 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// Typically, this value is not changed from its default value (1.0). It is /// Typically, this value is not changed from its default value (1.0). It is
/// used by [SliverAppBar] to animate the opacity of the toolbar when the app /// used by [SliverAppBar] to animate the opacity of the toolbar when the app
/// bar is scrolled. /// bar is scrolled.
/// {@endtemplate}
final double toolbarOpacity; final double toolbarOpacity;
/// {@template flutter.material.appbar.bottomOpacity}
/// How opaque the bottom part of the app bar is. /// How opaque the bottom part of the app bar is.
/// ///
/// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent. /// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent.
...@@ -441,25 +578,102 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -441,25 +578,102 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// Typically, this value is not changed from its default value (1.0). It is /// Typically, this value is not changed from its default value (1.0). It is
/// used by [SliverAppBar] to animate the opacity of the toolbar when the app /// used by [SliverAppBar] to animate the opacity of the toolbar when the app
/// bar is scrolled. /// bar is scrolled.
/// {@endtemplate}
final double bottomOpacity; final double bottomOpacity;
/// {@template flutter.material.appbar.preferredSize}
/// A size whose height is the sum of [toolbarHeight] and the [bottom] widget's /// A size whose height is the sum of [toolbarHeight] and the [bottom] widget's
/// preferred height. /// preferred height.
/// ///
/// [Scaffold] uses this size to set its app bar's height. /// [Scaffold] uses this size to set its app bar's height.
/// {@endtemplate}
@override @override
final Size preferredSize; final Size preferredSize;
/// {@template flutter.material.appbar.toolbarHeight}
/// Defines the height of the toolbar component of an [AppBar]. /// Defines the height of the toolbar component of an [AppBar].
/// ///
/// By default, the value of `toolbarHeight` is [kToolbarHeight]. /// By default, the value of `toolbarHeight` is [kToolbarHeight].
/// {@endtemplate}
final double? toolbarHeight; final double? toolbarHeight;
/// {@template flutter.material.appbar.leadingWidth}
/// Defines the width of [leading] widget. /// Defines the width of [leading] widget.
/// ///
/// By default, the value of `leadingWidth` is 56.0. /// By default, the value of `leadingWidth` is 56.0.
/// {@endtemplate}
final double? leadingWidth; final double? leadingWidth;
/// {@template flutter.material.appbar.backwardsCompatibility}
/// If true, preserves the original defaults for the [backgroundColor],
/// [iconTheme], [actionsIconTheme] properties, and the original use of
/// the [textTheme] and [brightness] properties.
///
/// This property is true by default.
///
/// This is a temporary property. When setting it to false is no
/// longer considereed a breaking change, it will be depreacted and
/// its default value will be changed to false. App developers are
/// encouraged to opt into the new features by setting it to false
/// and using the [foregroundColor] and [systemOverlayStyle]
/// properties as needed.
/// {@endtemplate}
final bool backwardsCompatibility;
/// {@template flutter.material.appbar.toolbarTextStyle}
/// The default text style for the AppBar's [leading], and
/// [actions] widgets, but not its [title].
///
/// If this property is null, then [AppBarTheme.toolbarTextStyle] of
/// [ThemeData.appBarTheme] is used. If that is also null, the default
/// value is a copy of the overall theme's [TextTheme.bodyText2]
/// [TextStyle], with color set to the app bar's [foregroundColor].
/// {@endtemplate}
///
/// See also:
///
/// * [titleTextStyle], which overrides the default text style for the [title].
/// * [DefaultTextStyle], which overrides the default text style for all of the
/// the widgets in a subtree.
final TextStyle? toolbarTextStyle;
/// {@template flutter.material.appbar.titleTextStyle}
/// The default text style for the AppBar's [title] widget.
///
/// If this property is null, then [AppBarTheme.titleTextStyle] of
/// [ThemeData.appBarTheme] is used. If that is also null, the default
/// value is a copy of the overall theme's [TextTheme.headline6]
/// [TextStyle], with color set to the app bar's [foregroundColor].
/// {@endtemplate}
///
/// See also:
///
/// * [toolbarTextStyle], which is the default text style for the AppBar's
/// [title], [leading], and [actions] widgets, also known as the
/// AppBar's "toolbar".
/// * [DefaultTextStyle], which overrides the default text style for all of the
/// the widgets in a subtree.
final TextStyle? titleTextStyle;
/// {@template flutter.material.appbar.systemOverlayStyle}
/// Specifies the style to use for the system overlays that overlap the AppBar.
///
/// If this property is null, then [SystemUiOverlayStyle.light] is used if the
/// overall theme is dark, [SystemUiOverlayStyle.dark] otherwise. Theme brightness
/// is defined by [ColorScheme.brightness] for [ThemeData.colorScheme].
///
/// The AppBar's descendants are built within a
/// `AnnotatedRegion<SystemUiOverlayStyle>` widget, which causes
/// [SystemChrome.setSystemUIOverlayStyle] to be called
/// automatically. Apps should not enclose an AppBar with their
/// own [AnnotatedRegion].
/// {@endtemplate}
//
/// See also:
/// * [SystemChrome.setSystemUIOverlayStyle]
final SystemUiOverlayStyle? systemOverlayStyle;
bool _getEffectiveCenterTitle(ThemeData theme) { bool _getEffectiveCenterTitle(ThemeData theme) {
if (centerTitle != null) if (centerTitle != null)
return centerTitle!; return centerTitle!;
...@@ -499,6 +713,7 @@ class _AppBarState extends State<AppBar> { ...@@ -499,6 +713,7 @@ class _AppBarState extends State<AppBar> {
assert(!widget.primary || debugCheckHasMediaQuery(context)); assert(!widget.primary || debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
final ColorScheme colorScheme = theme.colorScheme;
final AppBarTheme appBarTheme = AppBarTheme.of(context); final AppBarTheme appBarTheme = AppBarTheme.of(context);
final ScaffoldState? scaffold = Scaffold.maybeOf(context); final ScaffoldState? scaffold = Scaffold.maybeOf(context);
final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context); final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context);
...@@ -510,30 +725,57 @@ class _AppBarState extends State<AppBar> { ...@@ -510,30 +725,57 @@ class _AppBarState extends State<AppBar> {
final double toolbarHeight = widget.toolbarHeight ?? kToolbarHeight; final double toolbarHeight = widget.toolbarHeight ?? kToolbarHeight;
IconThemeData overallIconTheme = widget.iconTheme final Color backgroundColor = widget.backwardsCompatibility
? widget.backgroundColor
?? appBarTheme.color
?? theme.primaryColor
: widget.backgroundColor
?? appBarTheme.backgroundColor
?? (colorScheme.brightness == Brightness.dark ? colorScheme.surface : colorScheme.primary);
final Color foregroundColor = widget.foregroundColor
?? appBarTheme.foregroundColor
?? (colorScheme.brightness == Brightness.dark ? colorScheme.onSurface : colorScheme.onPrimary);
IconThemeData overallIconTheme = widget.backwardsCompatibility
? widget.iconTheme
?? appBarTheme.iconTheme
?? theme.primaryIconTheme
: widget.iconTheme
?? appBarTheme.iconTheme ?? appBarTheme.iconTheme
?? theme.primaryIconTheme; ?? theme.iconTheme.copyWith(color: foregroundColor);
IconThemeData actionsIconTheme = widget.actionsIconTheme IconThemeData actionsIconTheme = widget.actionsIconTheme
?? appBarTheme.actionsIconTheme ?? appBarTheme.actionsIconTheme
?? overallIconTheme; ?? overallIconTheme;
TextStyle? centerStyle = widget.textTheme?.headline6
?? appBarTheme.textTheme?.headline6 TextStyle? toolbarTextStyle = widget.backwardsCompatibility
?? theme.primaryTextTheme.headline6; ? widget.textTheme?.bodyText2
TextStyle? sideStyle = widget.textTheme?.bodyText2
?? appBarTheme.textTheme?.bodyText2 ?? appBarTheme.textTheme?.bodyText2
?? theme.primaryTextTheme.bodyText2; ?? theme.primaryTextTheme.bodyText2
: widget.toolbarTextStyle
?? appBarTheme.toolbarTextStyle
?? theme.textTheme.bodyText2?.copyWith(color: foregroundColor);
TextStyle? titleTextStyle = widget.backwardsCompatibility
? widget.textTheme?.headline6
?? appBarTheme.textTheme?.headline6
?? theme.primaryTextTheme.headline6
: widget.titleTextStyle
?? appBarTheme.titleTextStyle
?? theme.textTheme.headline6?.copyWith(color: foregroundColor);
if (widget.toolbarOpacity != 1.0) { if (widget.toolbarOpacity != 1.0) {
final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity); final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity);
if (centerStyle?.color != null) if (titleTextStyle?.color != null)
centerStyle = centerStyle!.copyWith(color: centerStyle.color!.withOpacity(opacity)); titleTextStyle = titleTextStyle!.copyWith(color: titleTextStyle.color!.withOpacity(opacity));
if (sideStyle?.color != null) if (toolbarTextStyle?.color != null)
sideStyle = sideStyle!.copyWith(color: sideStyle.color!.withOpacity(opacity)); toolbarTextStyle = toolbarTextStyle!.copyWith(color: toolbarTextStyle.color!.withOpacity(opacity));
overallIconTheme = overallIconTheme.copyWith( overallIconTheme = overallIconTheme.copyWith(
opacity: opacity * (overallIconTheme.opacity ?? 1.0) opacity: opacity * (overallIconTheme.opacity ?? 1.0),
); );
actionsIconTheme = actionsIconTheme.copyWith( actionsIconTheme = actionsIconTheme.copyWith(
opacity: opacity * (actionsIconTheme.opacity ?? 1.0) opacity: opacity * (actionsIconTheme.opacity ?? 1.0),
); );
} }
...@@ -582,7 +824,7 @@ class _AppBarState extends State<AppBar> { ...@@ -582,7 +824,7 @@ class _AppBarState extends State<AppBar> {
} }
title = DefaultTextStyle( title = DefaultTextStyle(
style: centerStyle!, style: titleTextStyle!,
softWrap: false, softWrap: false,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
child: title, child: title,
...@@ -644,7 +886,7 @@ class _AppBarState extends State<AppBar> { ...@@ -644,7 +886,7 @@ class _AppBarState extends State<AppBar> {
child: IconTheme.merge( child: IconTheme.merge(
data: overallIconTheme, data: overallIconTheme,
child: DefaultTextStyle( child: DefaultTextStyle(
style: sideStyle!, style: toolbarTextStyle!,
child: toolbar, child: toolbar,
), ),
), ),
...@@ -707,21 +949,20 @@ class _AppBarState extends State<AppBar> { ...@@ -707,21 +949,20 @@ class _AppBarState extends State<AppBar> {
], ],
); );
} }
final Brightness brightness = widget.brightness
?? appBarTheme.brightness final Brightness overlayStyleBrightness = widget.brightness ?? appBarTheme.brightness ?? colorScheme.brightness;
?? theme.primaryColorBrightness; final SystemUiOverlayStyle overlayStyle = widget.backwardsCompatibility
final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark ? (overlayStyleBrightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark)
? SystemUiOverlayStyle.light : widget.systemOverlayStyle
: SystemUiOverlayStyle.dark; ?? appBarTheme.systemOverlayStyle
?? (colorScheme.brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark);
return Semantics( return Semantics(
container: true, container: true,
child: AnnotatedRegion<SystemUiOverlayStyle>( child: AnnotatedRegion<SystemUiOverlayStyle>(
value: overlayStyle, value: overlayStyle,
child: Material( child: Material(
color: widget.backgroundColor color: backgroundColor,
?? appBarTheme.color
?? theme.primaryColor,
elevation: widget.elevation elevation: widget.elevation
?? appBarTheme.elevation ?? appBarTheme.elevation
?? _defaultElevation, ?? _defaultElevation,
...@@ -803,6 +1044,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -803,6 +1044,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
required this.shadowColor, required this.shadowColor,
required this.forceElevated, required this.forceElevated,
required this.backgroundColor, required this.backgroundColor,
required this.foregroundColor,
required this.brightness, required this.brightness,
required this.iconTheme, required this.iconTheme,
required this.actionsIconTheme, required this.actionsIconTheme,
...@@ -823,6 +1065,10 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -823,6 +1065,10 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
required this.shape, required this.shape,
required this.toolbarHeight, required this.toolbarHeight,
required this.leadingWidth, required this.leadingWidth,
required this.backwardsCompatibility,
required this.toolbarTextStyle,
required this.titleTextStyle,
required this.systemOverlayStyle,
}) : assert(primary || topPadding == 0.0), }) : assert(primary || topPadding == 0.0),
assert( assert(
!floating || (snapConfiguration == null && showOnScreenConfiguration == null) || vsync != null, !floating || (snapConfiguration == null && showOnScreenConfiguration == null) || vsync != null,
...@@ -840,6 +1086,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -840,6 +1086,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final Color? shadowColor; final Color? shadowColor;
final bool forceElevated; final bool forceElevated;
final Color? backgroundColor; final Color? backgroundColor;
final Color? foregroundColor;
final Brightness? brightness; final Brightness? brightness;
final IconThemeData? iconTheme; final IconThemeData? iconTheme;
final IconThemeData? actionsIconTheme; final IconThemeData? actionsIconTheme;
...@@ -856,7 +1103,10 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -856,7 +1103,10 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final ShapeBorder? shape; final ShapeBorder? shape;
final double? toolbarHeight; final double? toolbarHeight;
final double? leadingWidth; final double? leadingWidth;
final bool backwardsCompatibility;
final TextStyle? toolbarTextStyle;
final TextStyle? titleTextStyle;
final SystemUiOverlayStyle? systemOverlayStyle;
final double _bottomHeight; final double _bottomHeight;
@override @override
...@@ -905,6 +1155,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -905,6 +1155,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
elevation: forceElevated || overlapsContent || (pinned && shrinkOffset > maxExtent - minExtent) ? elevation ?? 4.0 : 0.0, elevation: forceElevated || overlapsContent || (pinned && shrinkOffset > maxExtent - minExtent) ? elevation ?? 4.0 : 0.0,
shadowColor: shadowColor, shadowColor: shadowColor,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
foregroundColor: foregroundColor,
brightness: brightness, brightness: brightness,
iconTheme: iconTheme, iconTheme: iconTheme,
actionsIconTheme: actionsIconTheme, actionsIconTheme: actionsIconTheme,
...@@ -918,6 +1169,10 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -918,6 +1169,10 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
bottomOpacity: pinned ? 1.0 : ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0)), bottomOpacity: pinned ? 1.0 : ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0)),
toolbarHeight: toolbarHeight, toolbarHeight: toolbarHeight,
leadingWidth: leadingWidth, leadingWidth: leadingWidth,
backwardsCompatibility: backwardsCompatibility,
toolbarTextStyle: toolbarTextStyle,
titleTextStyle: titleTextStyle,
systemOverlayStyle: systemOverlayStyle,
), ),
); );
return floating ? _FloatingAppBar(child: appBar) : appBar; return floating ? _FloatingAppBar(child: appBar) : appBar;
...@@ -935,6 +1190,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -935,6 +1190,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|| elevation != oldDelegate.elevation || elevation != oldDelegate.elevation
|| shadowColor != oldDelegate.shadowColor || shadowColor != oldDelegate.shadowColor
|| backgroundColor != oldDelegate.backgroundColor || backgroundColor != oldDelegate.backgroundColor
|| foregroundColor != oldDelegate.foregroundColor
|| brightness != oldDelegate.brightness || brightness != oldDelegate.brightness
|| iconTheme != oldDelegate.iconTheme || iconTheme != oldDelegate.iconTheme
|| actionsIconTheme != oldDelegate.actionsIconTheme || actionsIconTheme != oldDelegate.actionsIconTheme
...@@ -952,7 +1208,11 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -952,7 +1208,11 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|| showOnScreenConfiguration != oldDelegate.showOnScreenConfiguration || showOnScreenConfiguration != oldDelegate.showOnScreenConfiguration
|| forceElevated != oldDelegate.forceElevated || forceElevated != oldDelegate.forceElevated
|| toolbarHeight != oldDelegate.toolbarHeight || toolbarHeight != oldDelegate.toolbarHeight
|| leadingWidth != leadingWidth; || leadingWidth != oldDelegate.leadingWidth
|| backwardsCompatibility != oldDelegate.backwardsCompatibility
|| toolbarTextStyle != oldDelegate.toolbarTextStyle
|| titleTextStyle != oldDelegate.titleTextStyle
|| systemOverlayStyle != oldDelegate.systemOverlayStyle;
} }
@override @override
...@@ -1056,6 +1316,7 @@ class SliverAppBar extends StatefulWidget { ...@@ -1056,6 +1316,7 @@ class SliverAppBar extends StatefulWidget {
this.shadowColor, this.shadowColor,
this.forceElevated = false, this.forceElevated = false,
this.backgroundColor, this.backgroundColor,
this.foregroundColor,
this.brightness, this.brightness,
this.iconTheme, this.iconTheme,
this.actionsIconTheme, this.actionsIconTheme,
...@@ -1075,6 +1336,10 @@ class SliverAppBar extends StatefulWidget { ...@@ -1075,6 +1336,10 @@ class SliverAppBar extends StatefulWidget {
this.shape, this.shape,
this.toolbarHeight = kToolbarHeight, this.toolbarHeight = kToolbarHeight,
this.leadingWidth, this.leadingWidth,
this.backwardsCompatibility = true,
this.toolbarTextStyle,
this.titleTextStyle,
this.systemOverlayStyle,
}) : assert(automaticallyImplyLeading != null), }) : assert(automaticallyImplyLeading != null),
assert(forceElevated != null), assert(forceElevated != null),
assert(primary != null), assert(primary != null),
...@@ -1088,100 +1353,44 @@ class SliverAppBar extends StatefulWidget { ...@@ -1088,100 +1353,44 @@ class SliverAppBar extends StatefulWidget {
assert(collapsedHeight == null || collapsedHeight > toolbarHeight, 'The "collapsedHeight" argument has to be larger than [toolbarHeight].'), assert(collapsedHeight == null || collapsedHeight > toolbarHeight, 'The "collapsedHeight" argument has to be larger than [toolbarHeight].'),
super(key: key); super(key: key);
/// A widget to display before the [title]. /// {@macro flutter.material.appbar.leading}
/// ///
/// If this is null and [automaticallyImplyLeading] is set to true, the [AppBar] will /// This property is used to configure an [AppBar].
/// imply an appropriate widget. For example, if the [AppBar] is in a [Scaffold]
/// that also has a [Drawer], the [Scaffold] will fill this widget with an
/// [IconButton] that opens the drawer. If there's no [Drawer] and the parent
/// [Navigator] can go back, the [AppBar] will use a [BackButton] that calls
/// [Navigator.maybePop].
final Widget? leading; final Widget? leading;
/// Controls whether we should try to imply the leading widget if null. /// {@macro flutter.material.appbar.automaticallyImplyLeading}
/// ///
/// If true and [leading] is null, automatically try to deduce what the leading /// This property is used to configure an [AppBar].
/// widget should be. If false and [leading] is null, leading space is given to [title].
/// If leading widget is not null, this parameter has no effect.
final bool automaticallyImplyLeading; final bool automaticallyImplyLeading;
/// The primary widget displayed in the app bar. /// {@macro flutter.material.appbar.title}
/// ///
/// Typically a [Text] widget containing a description of the current contents /// This property is used to configure an [AppBar].
/// of the app.
final Widget? title; final Widget? title;
/// Widgets to display after the [title] widget. /// {@macro flutter.material.appbar.actions}
/// ///
/// Typically these widgets are [IconButton]s representing common operations. /// This property is used to configure an [AppBar].
/// For less common operations, consider using a [PopupMenuButton] as the
/// last action.
///
/// {@tool snippet}
///
/// ```dart
/// Scaffold(
/// body: CustomScrollView(
/// primary: true,
/// slivers: <Widget>[
/// SliverAppBar(
/// title: Text('Hello World'),
/// actions: <Widget>[
/// IconButton(
/// icon: Icon(Icons.shopping_cart),
/// tooltip: 'Open shopping cart',
/// onPressed: () {
/// // handle the press
/// },
/// ),
/// ],
/// ),
/// // ...rest of body...
/// ],
/// ),
/// )
/// ```
/// {@end-tool}
final List<Widget>? actions; final List<Widget>? actions;
/// This widget is stacked behind the toolbar and the tab bar. It's height will /// {@macro flutter.material.appbar.flexibleSpace}
/// be the same as the app bar's overall height.
///
/// When using [SliverAppBar.flexibleSpace], the [SliverAppBar.expandedHeight]
/// must be large enough to accommodate the [SliverAppBar.flexibleSpace] widget.
/// ///
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details. /// This property is used to configure an [AppBar].
final Widget? flexibleSpace; final Widget? flexibleSpace;
/// This widget appears across the bottom of the app bar. /// {@macro flutter.material.appbar.bottom}
/// ///
/// Typically a [TabBar]. Only widgets that implement [PreferredSizeWidget] can /// This property is used to configure an [AppBar].
/// be used at the bottom of an app bar.
///
/// See also:
///
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
final PreferredSizeWidget? bottom; final PreferredSizeWidget? bottom;
/// The z-coordinate at which to place this app bar when it is above other /// {@macro flutter.material.appbar.elevation}
/// content. This controls the size of the shadow below the app bar.
///
/// If this property is null, then [AppBarTheme.elevation] of
/// [ThemeData.appBarTheme] is used, if that is also null, the default value
/// is 4.
/// ///
/// If [forceElevated] is false, the elevation is ignored when the app bar has /// This property is used to configure an [AppBar].
/// no content underneath it. For example, if the app bar is [pinned] but no
/// content is scrolled under it, or if it scrolls with the content, then no
/// shadow is drawn, regardless of the value of [elevation].
final double? elevation; final double? elevation;
/// The color to paint the shadow below the app bar. Typically this should be set /// {@macro flutter.material.appbar.shadowColor}
/// along with [elevation].
/// ///
/// If this property is null, then [AppBarTheme.shadowColor] of /// This property is used to configure an [AppBar].
/// [ThemeData.appBarTheme] is used, if that is also null, the default value
/// is fully opaque black.
final Color? shadowColor; final Color? shadowColor;
/// Whether to show the shadow appropriate for the [elevation] even if the /// Whether to show the shadow appropriate for the [elevation] even if the
...@@ -1195,68 +1404,54 @@ class SliverAppBar extends StatefulWidget { ...@@ -1195,68 +1404,54 @@ class SliverAppBar extends StatefulWidget {
/// Ignored when [elevation] is zero. /// Ignored when [elevation] is zero.
final bool forceElevated; final bool forceElevated;
/// The color to use for the app bar's material. Typically this should be set /// {@macro flutter.material.appbar.backgroundColor}
/// along with [brightness], [iconTheme], [textTheme].
/// ///
/// If this property is null, then [AppBarTheme.color] of /// This property is used to configure an [AppBar].
/// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryColor] is used.
final Color? backgroundColor; final Color? backgroundColor;
/// The brightness of the app bar's material. Typically this is set along /// {@macro flutter.material.appbar.foregroundColor}
/// with [backgroundColor], [iconTheme], [textTheme].
/// ///
/// If this property is null, then [AppBarTheme.brightness] of /// This property is used to configure an [AppBar].
/// [ThemeData.appBarTheme] is used. If that is also null, then final Color? foregroundColor;
/// [ThemeData.primaryColorBrightness] is used.
/// {@macro flutter.material.appbar.brightness}
///
/// This property is used to configure an [AppBar].
final Brightness? brightness; final Brightness? brightness;
/// The color, opacity, and size to use for app bar icons. Typically this /// {@macro flutter.material.appbar.iconTheme}
/// is set along with [backgroundColor], [brightness], [textTheme].
/// ///
/// If this property is null, then [AppBarTheme.iconTheme] of /// This property is used to configure an [AppBar].
/// [ThemeData.appBarTheme] is used, if that is also null, then
/// [ThemeData.primaryIconTheme] is used.
final IconThemeData? iconTheme; final IconThemeData? iconTheme;
/// The color, opacity, and size to use for trailing app bar icons. This /// {@macro flutter.material.appbar.actionsIconTheme}
/// should only be used when the trailing icons should be themed differently
/// than the leading icons.
/// ///
/// If this property is null, then [AppBarTheme.actionsIconTheme] of /// This property is used to configure an [AppBar].
/// [ThemeData.appBarTheme] is used, if that is also null, then this falls
/// back to [iconTheme].
final IconThemeData? actionsIconTheme; final IconThemeData? actionsIconTheme;
/// The typographic styles to use for text in the app bar. Typically this is /// {@macro flutter.material.appbar.textTheme}
/// set along with [brightness] [backgroundColor], [iconTheme].
/// ///
/// If this property is null, then [AppBarTheme.textTheme] of /// This property is used to configure an [AppBar].
/// [ThemeData.appBarTheme] is used, if that is also null, then
/// [ThemeData.primaryTextTheme] is used.
final TextTheme? textTheme; final TextTheme? textTheme;
/// Whether this app bar is being displayed at the top of the screen. /// {@macro flutter.material.appbar.primary}
/// ///
/// If this is true, the top padding specified by the [MediaQuery] will be /// This property is used to configure an [AppBar].
/// added to the top of the toolbar.
final bool primary; final bool primary;
/// Whether the title should be centered. /// {@macro flutter.material.appbar.centerTitle}
/// ///
/// Defaults to being adapted to the current [TargetPlatform]. /// This property is used to configure an [AppBar].
final bool? centerTitle; final bool? centerTitle;
/// Whether the title should be wrapped with header [Semantics]. /// {@macro flutter.material.appbar.excludeHeaderSemantics}
/// ///
/// Defaults to false. /// This property is used to configure an [AppBar].
final bool excludeHeaderSemantics; final bool excludeHeaderSemantics;
/// The spacing around [title] content on the horizontal axis. This spacing is /// {@macro flutter.material.appbar.titleSpacing}
/// applied even if there is no [leading] content or [actions]. If you want
/// [title] to take all the space available, set this value to 0.0.
/// ///
/// Defaults to [NavigationToolbar.kMiddleSpacing]. /// This property is used to configure an [AppBar].
final double? titleSpacing; final double? titleSpacing;
/// Defines the height of the app bar when it is collapsed. /// Defines the height of the app bar when it is collapsed.
...@@ -1328,9 +1523,9 @@ class SliverAppBar extends StatefulWidget { ...@@ -1328,9 +1523,9 @@ class SliverAppBar extends StatefulWidget {
/// behavior of the app bar in combination with [floating]. /// behavior of the app bar in combination with [floating].
final bool pinned; final bool pinned;
/// The material's shape as well as its shadow. /// {@macro flutter.material.appbar.shape}
/// ///
/// A shadow is only displayed if the [elevation] is greater than zero. /// This property is used to configure an [AppBar].
final ShapeBorder? shape; final ShapeBorder? shape;
/// If [snap] and [floating] are true then the floating app bar will "snap" /// If [snap] and [floating] are true then the floating app bar will "snap"
...@@ -1380,16 +1575,36 @@ class SliverAppBar extends StatefulWidget { ...@@ -1380,16 +1575,36 @@ class SliverAppBar extends StatefulWidget {
/// offset specified by [stretchTriggerOffset]. /// offset specified by [stretchTriggerOffset].
final AsyncCallback? onStretchTrigger; final AsyncCallback? onStretchTrigger;
/// Defines the height of the toolbar component of an [AppBar]. /// {@macro flutter.material.appbar.toolbarHeight}
/// ///
/// By default, the value of `toolbarHeight` is [kToolbarHeight]. /// This property is used to configure an [AppBar].
final double toolbarHeight; final double toolbarHeight;
/// Defines the width of [leading] widget. /// {@macro flutter.material.appbar.leadingWidth}
/// ///
/// By default, the value of `leadingWidth` is 56.0. /// This property is used to configure an [AppBar].
final double? leadingWidth; final double? leadingWidth;
/// {@macro flutter.material.appbar.backwardsCompatibility}
///
/// This property is used to configure an [AppBar].
final bool backwardsCompatibility;
/// {@macro flutter.material.appbar.toolbarTextStyle}
///
/// This property is used to configure an [AppBar].
final TextStyle? toolbarTextStyle;
/// {@macro flutter.material.appbar.titleTextStyle}
///
/// This property is used to configure an [AppBar].
final TextStyle? titleTextStyle;
/// {@macro flutter.material.appbar.systemOverlayStyle}
///
/// This property is used to configure an [AppBar].
final SystemUiOverlayStyle? systemOverlayStyle;
@override @override
_SliverAppBarState createState() => _SliverAppBarState(); _SliverAppBarState createState() => _SliverAppBarState();
} }
...@@ -1470,6 +1685,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix ...@@ -1470,6 +1685,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
shadowColor: widget.shadowColor, shadowColor: widget.shadowColor,
forceElevated: widget.forceElevated, forceElevated: widget.forceElevated,
backgroundColor: widget.backgroundColor, backgroundColor: widget.backgroundColor,
foregroundColor: widget.foregroundColor,
brightness: widget.brightness, brightness: widget.brightness,
iconTheme: widget.iconTheme, iconTheme: widget.iconTheme,
actionsIconTheme: widget.actionsIconTheme, actionsIconTheme: widget.actionsIconTheme,
...@@ -1489,6 +1705,10 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix ...@@ -1489,6 +1705,10 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
showOnScreenConfiguration: _showOnScreenConfiguration, showOnScreenConfiguration: _showOnScreenConfiguration,
toolbarHeight: widget.toolbarHeight, toolbarHeight: widget.toolbarHeight,
leadingWidth: widget.leadingWidth, leadingWidth: widget.leadingWidth,
backwardsCompatibility: widget.backwardsCompatibility,
toolbarTextStyle: widget.toolbarTextStyle,
titleTextStyle: widget.titleTextStyle,
systemOverlayStyle: widget.systemOverlayStyle,
), ),
), ),
); );
......
...@@ -5,14 +5,16 @@ ...@@ -5,14 +5,16 @@
import 'dart:ui' show lerpDouble; import 'dart:ui' show lerpDouble;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'text_theme.dart'; import 'text_theme.dart';
import 'theme.dart'; import 'theme.dart';
/// Defines default property values for descendant [AppBar] widgets. /// Overrides the default values of visual properties for descendant
/// [AppBar] widgets.
/// ///
/// Descendant widgets obtain the current [AppBarTheme] object using /// Descendant widgets obtain the current [AppBarTheme] object with
/// `AppBarTheme.of(context)`. Instances of [AppBarTheme] can be customized /// `AppBarTheme.of(context)`. Instances of [AppBarTheme] can be customized
/// with [AppBarTheme.copyWith]. /// with [AppBarTheme.copyWith].
/// ///
...@@ -20,19 +22,16 @@ import 'theme.dart'; ...@@ -20,19 +22,16 @@ import 'theme.dart';
/// [ThemeData.appBarTheme]. /// [ThemeData.appBarTheme].
/// ///
/// All [AppBarTheme] properties are `null` by default. When null, the [AppBar] /// All [AppBarTheme] properties are `null` by default. When null, the [AppBar]
/// will use the values from [ThemeData] if they exist, otherwise it will /// compute its own default values, typically based on the overall theme's
/// provide its own defaults. /// [ThemeData.colorScheme], [ThemeData.textTheme], and [ThemeData.iconTheme].
///
/// See also:
///
/// * [ThemeData], which describes the overall theme information for the
/// application.
@immutable @immutable
class AppBarTheme with Diagnosticable { class AppBarTheme with Diagnosticable {
/// Creates a theme that can be used for [ThemeData.appBarTheme]. /// Creates a theme that can be used for [ThemeData.appBarTheme].
const AppBarTheme({ const AppBarTheme({
this.brightness, this.brightness,
this.color, this.color,
this.backgroundColor,
this.foregroundColor,
this.elevation, this.elevation,
this.shadowColor, this.shadowColor,
this.iconTheme, this.iconTheme,
...@@ -40,69 +39,151 @@ class AppBarTheme with Diagnosticable { ...@@ -40,69 +39,151 @@ class AppBarTheme with Diagnosticable {
this.textTheme, this.textTheme,
this.centerTitle, this.centerTitle,
this.titleSpacing, this.titleSpacing,
this.toolbarTextStyle,
this.titleTextStyle,
this.systemOverlayStyle,
}); });
/// Default value for [AppBar.brightness]. /// This property is obsolete, please use [systemOverlayStyle] instead.
///
/// Overrides the default value of the obsolete [AppBar.brightness]
/// property which implicitly defines [AppBar.systemOverlayStyle] in
/// all descendant [AppBar] widgets.
/// ///
/// If null, [AppBar] uses [ThemeData.primaryColorBrightness]. /// See also:
///
/// * [systemOverlayStyle], which overrides the default value of
/// [AppBar.systemOverlayStyle] in all descendant [AppBar] widgets.
/// * [AppBar.backwardsCompatibility], which forces [AppBar] to depend
/// on this obsolete property.
final Brightness? brightness; final Brightness? brightness;
/// Default value for [AppBar.backgroundColor]. /// Obsolete property that overrides the default value of
/// [AppBar.backgroundColor] in all descendant [AppBar] widgets.
///
/// See also:
/// ///
/// If null, [AppBar] uses [ThemeData.primaryColor]. /// * [backgroundColor], which serves this same purpose
/// as this property, but has a consistent name.
/// * [AppBar.backwardsCompatibility], which forces [AppBar] to depend
/// on this obsolete property.
final Color? color; final Color? color;
/// Default value for [AppBar.elevation]. /// Overrides the default value of [AppBar.backgroundColor] in all
/// descendant [AppBar] widgets.
/// ///
/// If null, [AppBar] uses a default value of 4.0. /// See also:
final double? elevation; ///
/// * [foregroundColor], which overrides the default value for
/// [AppBar.foregroundColor] in all descendant widgets.
final Color? backgroundColor;
/// Default value for [AppBar.shadowColor]. /// Overrides the default value of [AppBar.foregroundColor] in all
/// descendant widgets.
///
/// See also:
/// ///
/// If null, [AppBar] uses a default value of fully opaque black. /// * [backgroundColor], which overrides the default value for
/// [AppBar.backgroundColor] in all descendant [AppBar] widgets.
final Color? foregroundColor;
/// Overrides the default value of [AppBar.elevation] in all
/// descendant [AppBar] widgets.
final double? elevation;
/// Overrides the default value for [AppBar.shadowColor] in all
/// descendant widgets.
final Color? shadowColor; final Color? shadowColor;
/// Default value for [AppBar.iconTheme]. /// Overrides the default value of [AppBar.iconTheme] in all
/// descendant [AppBar] widgets.
/// ///
/// If null, [AppBar] uses [ThemeData.primaryIconTheme]. /// See also:
///
/// * [actionsIconTheme], which overrides the default value for
/// [AppBar.actionsIconTheme] in all descendant [AppBar] widgets.
/// * [foregroundColor], which overrides the default value
/// [AppBar.foregroundColor] in all descendant widgets.
final IconThemeData? iconTheme; final IconThemeData? iconTheme;
/// Default value for [AppBar.actionsIconTheme]. /// Overrides the default value of [AppBar.actionsIconTheme] in all
/// descendant widgets.
///
/// See also:
/// ///
/// If null, [AppBar] uses [ThemeData.primaryIconTheme]. /// * [iconTheme], which overrides the default value for
/// [AppBar.iconTheme] in all descendant widgets.
/// * [foregroundColor], which overrides the default value
/// [AppBar.foregroundColor] in all descendant widgets.
final IconThemeData? actionsIconTheme; final IconThemeData? actionsIconTheme;
/// Default value for [AppBar.textTheme]. /// Overrides the default value of the obsolete [AppBar.textTheme]
/// property in all descendant [AppBar] widgets.
///
/// See also:
/// ///
/// If null, [AppBar] uses [ThemeData.primaryTextTheme]. /// * [toolbarTextStyle], which overrides the default value for
/// [AppBar.toolbarTextStyle in all descendant [AppBar] widgets.
/// * [titleTextStyle], which overrides the default value for
/// [AppBar.titleTextStyle in all descendant [AppBar] widgets.
final TextTheme? textTheme; final TextTheme? textTheme;
/// Default value for [AppBar.centerTitle]. /// Overrides the default value for [AppBar.centerTitle].
/// /// property in all descendant widgets.
/// If null, the value is adapted to current [TargetPlatform].
final bool? centerTitle; final bool? centerTitle;
/// Default value for [AppBar.titleSpacing]. /// Overrides the default value for the obsolete [AppBar.titleSpacing]
/// property in all descendant [AppBar] widgets.
/// ///
/// If null, [AppBar] uses default value of [NavigationToolbar.kMiddleSpacing]. /// If null, [AppBar] uses default value of [NavigationToolbar.kMiddleSpacing].
final double? titleSpacing; final double? titleSpacing;
/// Overrides the default value for the obsolete [AppBar.toolbarTextStyle]
/// property in all descendant [AppBar] widgets.
///
/// See also:
///
/// * [titleTextStyle], which overrides the default of [AppBar.titleTextStyle]
/// in all descendant [AppBar] widgets.
final TextStyle? toolbarTextStyle;
/// Overrides the default value of [AppBar.titleTextStyle]
/// property in all descendant [AppBar] widgets.
///
/// See also:
///
/// * [toolbarTextStyle], which overrides the default of [AppBar.toolbarTextStyle]
/// in all descendant [AppBar] widgets.
final TextStyle? titleTextStyle;
/// Overrides the default value of [AppBar.systemOverlayStyle]
/// property in all descendant [AppBar] widgets.
final SystemUiOverlayStyle? systemOverlayStyle;
/// Creates a copy of this object with the given fields replaced with the /// Creates a copy of this object with the given fields replaced with the
/// new values. /// new values.
AppBarTheme copyWith({ AppBarTheme copyWith({
IconThemeData? actionsIconTheme, IconThemeData? actionsIconTheme,
Brightness? brightness, Brightness? brightness,
Color? color, Color? color,
Color? backgroundColor,
Color? foregroundColor,
double? elevation, double? elevation,
Color? shadowColor, Color? shadowColor,
IconThemeData? iconTheme, IconThemeData? iconTheme,
TextTheme? textTheme, TextTheme? textTheme,
bool? centerTitle, bool? centerTitle,
double? titleSpacing, double? titleSpacing,
TextStyle? toolbarTextStyle,
TextStyle? titleTextStyle,
SystemUiOverlayStyle? systemOverlayStyle,
}) { }) {
return AppBarTheme( return AppBarTheme(
brightness: brightness ?? this.brightness, brightness: brightness ?? this.brightness,
color: color ?? this.color, color: color ?? this.color,
backgroundColor: backgroundColor ?? this.backgroundColor,
foregroundColor: foregroundColor ?? this.foregroundColor,
elevation: elevation ?? this.elevation, elevation: elevation ?? this.elevation,
shadowColor: shadowColor ?? this.shadowColor, shadowColor: shadowColor ?? this.shadowColor,
iconTheme: iconTheme ?? this.iconTheme, iconTheme: iconTheme ?? this.iconTheme,
...@@ -110,6 +191,9 @@ class AppBarTheme with Diagnosticable { ...@@ -110,6 +191,9 @@ class AppBarTheme with Diagnosticable {
textTheme: textTheme ?? this.textTheme, textTheme: textTheme ?? this.textTheme,
centerTitle: centerTitle ?? this.centerTitle, centerTitle: centerTitle ?? this.centerTitle,
titleSpacing: titleSpacing ?? this.titleSpacing, titleSpacing: titleSpacing ?? this.titleSpacing,
toolbarTextStyle: toolbarTextStyle ?? this.toolbarTextStyle,
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
systemOverlayStyle: systemOverlayStyle ?? this.systemOverlayStyle,
); );
} }
...@@ -128,6 +212,8 @@ class AppBarTheme with Diagnosticable { ...@@ -128,6 +212,8 @@ class AppBarTheme with Diagnosticable {
return AppBarTheme( return AppBarTheme(
brightness: t < 0.5 ? a?.brightness : b?.brightness, brightness: t < 0.5 ? a?.brightness : b?.brightness,
color: Color.lerp(a?.color, b?.color, t), color: Color.lerp(a?.color, b?.color, t),
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
foregroundColor: Color.lerp(a?.foregroundColor, b?.foregroundColor, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t), elevation: lerpDouble(a?.elevation, b?.elevation, t),
shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t), iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t),
...@@ -135,6 +221,9 @@ class AppBarTheme with Diagnosticable { ...@@ -135,6 +221,9 @@ class AppBarTheme with Diagnosticable {
textTheme: TextTheme.lerp(a?.textTheme, b?.textTheme, t), textTheme: TextTheme.lerp(a?.textTheme, b?.textTheme, t),
centerTitle: t < 0.5 ? a?.centerTitle : b?.centerTitle, centerTitle: t < 0.5 ? a?.centerTitle : b?.centerTitle,
titleSpacing: lerpDouble(a?.titleSpacing, b?.titleSpacing, t), titleSpacing: lerpDouble(a?.titleSpacing, b?.titleSpacing, 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,
); );
} }
...@@ -143,6 +232,8 @@ class AppBarTheme with Diagnosticable { ...@@ -143,6 +232,8 @@ class AppBarTheme with Diagnosticable {
return hashValues( return hashValues(
brightness, brightness,
color, color,
backgroundColor,
foregroundColor,
elevation, elevation,
shadowColor, shadowColor,
iconTheme, iconTheme,
...@@ -150,6 +241,9 @@ class AppBarTheme with Diagnosticable { ...@@ -150,6 +241,9 @@ class AppBarTheme with Diagnosticable {
textTheme, textTheme,
centerTitle, centerTitle,
titleSpacing, titleSpacing,
toolbarTextStyle,
titleTextStyle,
systemOverlayStyle,
); );
} }
...@@ -162,13 +256,18 @@ class AppBarTheme with Diagnosticable { ...@@ -162,13 +256,18 @@ class AppBarTheme with Diagnosticable {
return other is AppBarTheme return other is AppBarTheme
&& other.brightness == brightness && other.brightness == brightness
&& other.color == color && other.color == color
&& other.backgroundColor == backgroundColor
&& other.foregroundColor == foregroundColor
&& other.elevation == elevation && other.elevation == elevation
&& other.shadowColor == shadowColor && other.shadowColor == shadowColor
&& other.iconTheme == iconTheme && other.iconTheme == iconTheme
&& other.actionsIconTheme == actionsIconTheme && other.actionsIconTheme == actionsIconTheme
&& other.textTheme == textTheme && other.textTheme == textTheme
&& other.centerTitle == centerTitle && other.centerTitle == centerTitle
&& other.titleSpacing == titleSpacing; && other.titleSpacing == titleSpacing
&& other.toolbarTextStyle == toolbarTextStyle
&& other.titleTextStyle == titleTextStyle
&& other.systemOverlayStyle == systemOverlayStyle;
} }
@override @override
...@@ -176,6 +275,8 @@ class AppBarTheme with Diagnosticable { ...@@ -176,6 +275,8 @@ class AppBarTheme with Diagnosticable {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<Brightness>('brightness', brightness, defaultValue: null)); properties.add(DiagnosticsProperty<Brightness>('brightness', brightness, defaultValue: null));
properties.add(ColorProperty('color', color, defaultValue: null)); properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
properties.add(ColorProperty('foregroundColor', foregroundColor, defaultValue: null));
properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null)); properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null));
properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
properties.add(DiagnosticsProperty<IconThemeData>('iconTheme', iconTheme, defaultValue: null)); properties.add(DiagnosticsProperty<IconThemeData>('iconTheme', iconTheme, defaultValue: null));
...@@ -183,5 +284,7 @@ class AppBarTheme with Diagnosticable { ...@@ -183,5 +284,7 @@ class AppBarTheme with Diagnosticable {
properties.add(DiagnosticsProperty<TextTheme>('textTheme', textTheme, defaultValue: null)); properties.add(DiagnosticsProperty<TextTheme>('textTheme', textTheme, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('centerTitle', centerTitle, defaultValue: null)); properties.add(DiagnosticsProperty<bool>('centerTitle', centerTitle, defaultValue: null));
properties.add(DiagnosticsProperty<double>('titleSpacing', titleSpacing, defaultValue: null)); properties.add(DiagnosticsProperty<double>('titleSpacing', titleSpacing, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('toolbarTextStyle', toolbarTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null));
} }
} }
...@@ -27,6 +27,7 @@ Widget buildSliverAppBarApp({ ...@@ -27,6 +27,7 @@ Widget buildSliverAppBarApp({
primary: true, primary: true,
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
title: const Text('AppBar Title'), title: const Text('AppBar Title'),
floating: floating, floating: floating,
pinned: pinned, pinned: pinned,
...@@ -72,6 +73,7 @@ void main() { ...@@ -72,6 +73,7 @@ void main() {
theme: ThemeData(platform: TargetPlatform.android), theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('X'), title: const Text('X'),
), ),
), ),
...@@ -92,6 +94,7 @@ void main() { ...@@ -92,6 +94,7 @@ void main() {
theme: ThemeData(platform: platform), theme: ThemeData(platform: platform),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('X'), title: const Text('X'),
), ),
), ),
...@@ -110,6 +113,7 @@ void main() { ...@@ -110,6 +113,7 @@ void main() {
theme: ThemeData(platform: platform), theme: ThemeData(platform: platform),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('X'), title: const Text('X'),
actions: const <Widget>[ actions: const <Widget>[
Icon(Icons.thumb_up), Icon(Icons.thumb_up),
...@@ -131,6 +135,7 @@ void main() { ...@@ -131,6 +135,7 @@ void main() {
theme: ThemeData(platform: platform), theme: ThemeData(platform: platform),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('X'), title: const Text('X'),
actions: const <Widget>[ actions: const <Widget>[
Icon(Icons.thumb_up), Icon(Icons.thumb_up),
...@@ -153,6 +158,7 @@ void main() { ...@@ -153,6 +158,7 @@ void main() {
theme: ThemeData(platform: TargetPlatform.android), theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: true, centerTitle: true,
title: const Text('X'), title: const Text('X'),
), ),
...@@ -172,6 +178,7 @@ void main() { ...@@ -172,6 +178,7 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: false, centerTitle: false,
title: const Placeholder(key: Key('X')), title: const Placeholder(key: Key('X')),
), ),
...@@ -191,6 +198,7 @@ void main() { ...@@ -191,6 +198,7 @@ void main() {
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: false, centerTitle: false,
title: const Placeholder(key: Key('X')), title: const Placeholder(key: Key('X')),
), ),
...@@ -209,6 +217,7 @@ void main() { ...@@ -209,6 +217,7 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: false, centerTitle: false,
titleSpacing: 32.0, titleSpacing: 32.0,
title: const Placeholder(key: Key('X')), title: const Placeholder(key: Key('X')),
...@@ -229,6 +238,7 @@ void main() { ...@@ -229,6 +238,7 @@ void main() {
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: false, centerTitle: false,
titleSpacing: 32.0, titleSpacing: 32.0,
title: const Placeholder(key: Key('X')), title: const Placeholder(key: Key('X')),
...@@ -250,6 +260,7 @@ void main() { ...@@ -250,6 +260,7 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: false, centerTitle: false,
title: const Text('X'), title: const Text('X'),
), ),
...@@ -271,6 +282,7 @@ void main() { ...@@ -271,6 +282,7 @@ void main() {
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: false, centerTitle: false,
title: const Text('X'), title: const Text('X'),
), ),
...@@ -296,6 +308,7 @@ void main() { ...@@ -296,6 +308,7 @@ void main() {
return MaterialApp( return MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
leading: leading, leading: leading,
centerTitle: false, centerTitle: false,
title: Container( title: Container(
...@@ -354,6 +367,7 @@ void main() { ...@@ -354,6 +367,7 @@ void main() {
return MaterialApp( return MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
leading: leading, leading: leading,
centerTitle: true, centerTitle: true,
title: Container( title: Container(
...@@ -408,6 +422,7 @@ void main() { ...@@ -408,6 +422,7 @@ void main() {
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
leading: leading, leading: leading,
centerTitle: true, centerTitle: true,
title: Container( title: Container(
...@@ -453,6 +468,7 @@ void main() { ...@@ -453,6 +468,7 @@ void main() {
home: SizedBox( home: SizedBox(
height: kToolbarHeight, height: kToolbarHeight,
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: const Text('L'), leading: const Text('L'),
title: const Text('No Scaffold'), title: const Text('No Scaffold'),
actions: const <Widget>[Text('A1'), Text('A2')], actions: const <Widget>[Text('A1'), Text('A2')],
...@@ -476,6 +492,7 @@ void main() { ...@@ -476,6 +492,7 @@ void main() {
width: 0.0, width: 0.0,
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('X'), title: const Text('X'),
), ),
), ),
...@@ -499,6 +516,7 @@ void main() { ...@@ -499,6 +516,7 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
key: appBarKey, key: appBarKey,
leading: SizedBox(key: leadingKey, height: 50.0), leading: SizedBox(key: leadingKey, height: 50.0),
title: SizedBox(key: titleKey, height: 40.0), title: SizedBox(key: titleKey, height: 40.0),
...@@ -526,6 +544,7 @@ void main() { ...@@ -526,6 +544,7 @@ void main() {
theme: ThemeData(platform: TargetPlatform.android), theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('X'), title: const Text('X'),
), ),
drawer: Column(), // Doesn't really matter. Triggers a hamburger regardless. drawer: Column(), // Doesn't really matter. Triggers a hamburger regardless.
...@@ -544,6 +563,7 @@ void main() { ...@@ -544,6 +563,7 @@ void main() {
theme: ThemeData(platform: TargetPlatform.android), theme: ThemeData(platform: TargetPlatform.android),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('X'), title: const Text('X'),
actions: const <Widget> [ actions: const <Widget> [
IconButton( IconButton(
...@@ -890,6 +910,7 @@ void main() { ...@@ -890,6 +910,7 @@ void main() {
home: CustomScrollView( home: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
title: const Text('Title'), title: const Text('Title'),
forceElevated: forceElevated, forceElevated: forceElevated,
), ),
...@@ -945,7 +966,10 @@ void main() { ...@@ -945,7 +966,10 @@ void main() {
data: topPadding100, data: topPadding100,
child: Scaffold( child: Scaffold(
primary: true, primary: true,
appBar: AppBar(title: const Text('title')), appBar: AppBar(
backwardsCompatibility: false,
title: const Text('title')
),
), ),
), ),
), ),
...@@ -968,6 +992,7 @@ void main() { ...@@ -968,6 +992,7 @@ void main() {
child: Scaffold( child: Scaffold(
primary: false, primary: false,
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
bottom: PreferredSize( bottom: PreferredSize(
preferredSize: const Size.fromHeight(200.0), preferredSize: const Size.fromHeight(200.0),
child: Container(), child: Container(),
...@@ -994,6 +1019,7 @@ void main() { ...@@ -994,6 +1019,7 @@ void main() {
child: Scaffold( child: Scaffold(
primary: true, primary: true,
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
bottom: PreferredSize( bottom: PreferredSize(
preferredSize: const Size.fromHeight(200.0), preferredSize: const Size.fromHeight(200.0),
child: Container(), child: Container(),
...@@ -1018,6 +1044,7 @@ void main() { ...@@ -1018,6 +1044,7 @@ void main() {
child: MediaQuery( child: MediaQuery(
data: topPadding100, data: topPadding100,
child: AppBar( child: AppBar(
backwardsCompatibility: false,
primary: false, primary: false,
title: const Text('title'), title: const Text('title'),
), ),
...@@ -1047,6 +1074,7 @@ void main() { ...@@ -1047,6 +1074,7 @@ void main() {
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
AppBar( AppBar(
backwardsCompatibility: false,
title: const Text('title'), title: const Text('title'),
), ),
], ],
...@@ -1084,7 +1112,10 @@ void main() { ...@@ -1084,7 +1112,10 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
drawer: const Drawer(), drawer: const Drawer(),
appBar: AppBar(automaticallyImplyLeading: false), appBar: AppBar(
backwardsCompatibility: false,
automaticallyImplyLeading: false,
),
), ),
), ),
); );
...@@ -1098,6 +1129,7 @@ void main() { ...@@ -1098,6 +1129,7 @@ void main() {
MaterialApp( MaterialApp(
home: Center( home: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
title: const Text('Abc'), title: const Text('Abc'),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
...@@ -1139,6 +1171,7 @@ void main() { ...@@ -1139,6 +1171,7 @@ void main() {
MaterialApp( MaterialApp(
home: Center( home: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: Placeholder(key: key), leading: Placeholder(key: key),
title: const Text('Abc'), title: const Text('Abc'),
actions: const <Widget>[ actions: const <Widget>[
...@@ -1160,6 +1193,7 @@ void main() { ...@@ -1160,6 +1193,7 @@ void main() {
MaterialApp( MaterialApp(
home: Center( home: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: Placeholder(key: key), leading: Placeholder(key: key),
title: const Text('Abc'), title: const Text('Abc'),
actions: const <Widget>[ actions: const <Widget>[
...@@ -1190,6 +1224,7 @@ void main() { ...@@ -1190,6 +1224,7 @@ void main() {
MaterialApp( MaterialApp(
home: Center( home: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: Placeholder(key: key), leading: Placeholder(key: key),
title: const Text('Abc'), title: const Text('Abc'),
actions: const <Widget>[ actions: const <Widget>[
...@@ -1231,6 +1266,7 @@ void main() { ...@@ -1231,6 +1266,7 @@ void main() {
MaterialApp( MaterialApp(
home: Center( home: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: Placeholder(key: key), leading: Placeholder(key: key),
title: const Text('Abc'), title: const Text('Abc'),
actions: const <Widget>[ actions: const <Widget>[
...@@ -1278,6 +1314,7 @@ void main() { ...@@ -1278,6 +1314,7 @@ void main() {
child: Scaffold( child: Scaffold(
primary: false, primary: false,
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
leading: Placeholder(key: leadingKey), // Forced to 56x56, see _kLeadingWidth in app_bar.dart. leading: Placeholder(key: leadingKey), // Forced to 56x56, see _kLeadingWidth in app_bar.dart.
title: Placeholder(key: titleKey, fallbackHeight: kToolbarHeight), title: Placeholder(key: titleKey, fallbackHeight: kToolbarHeight),
actions: <Widget>[ Placeholder(key: trailingKey, fallbackWidth: 10) ], actions: <Widget>[ Placeholder(key: trailingKey, fallbackWidth: 10) ],
...@@ -1322,6 +1359,7 @@ void main() { ...@@ -1322,6 +1359,7 @@ void main() {
primary: true, primary: true,
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
leading: Placeholder(key: leadingKey), leading: Placeholder(key: leadingKey),
title: Placeholder(key: titleKey, fallbackHeight: kToolbarHeight), title: Placeholder(key: titleKey, fallbackHeight: kToolbarHeight),
actions: <Widget>[ Placeholder(key: trailingKey) ], actions: <Widget>[ Placeholder(key: trailingKey) ],
...@@ -1359,6 +1397,7 @@ void main() { ...@@ -1359,6 +1397,7 @@ void main() {
primary: true, primary: true,
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
leading: Placeholder(key: leadingKey), leading: Placeholder(key: leadingKey),
title: Placeholder(key: titleKey), title: Placeholder(key: titleKey),
actions: <Widget>[ Placeholder(key: trailingKey) ], actions: <Widget>[ Placeholder(key: trailingKey) ],
...@@ -1380,6 +1419,7 @@ void main() { ...@@ -1380,6 +1419,7 @@ void main() {
MaterialApp( MaterialApp(
home: Center( home: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: const Text('Leading'), leading: const Text('Leading'),
title: const Text('Title'), title: const Text('Title'),
actions: const <Widget>[ actions: const <Widget>[
...@@ -1465,6 +1505,7 @@ void main() { ...@@ -1465,6 +1505,7 @@ void main() {
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Center( child: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: const Text('Leading'), leading: const Text('Leading'),
title: const Text('Title'), title: const Text('Title'),
actions: const <Widget>[ actions: const <Widget>[
...@@ -1553,6 +1594,7 @@ void main() { ...@@ -1553,6 +1594,7 @@ void main() {
MaterialApp( MaterialApp(
home: Center( home: Center(
child: AppBar( child: AppBar(
backwardsCompatibility: false,
leading: const Text('Leading'), leading: const Text('Leading'),
title: const ExcludeSemantics(child: Text('Title')), title: const ExcludeSemantics(child: Text('Title')),
excludeHeaderSemantics: true, excludeHeaderSemantics: true,
...@@ -1610,6 +1652,7 @@ void main() { ...@@ -1610,6 +1652,7 @@ void main() {
home: CustomScrollView( home: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
leading: Text('Leading'), leading: Text('Leading'),
flexibleSpace: ExcludeSemantics(child: Text('Title')), flexibleSpace: ExcludeSemantics(child: Text('Title')),
actions: <Widget>[Text('Action 1')], actions: <Widget>[Text('Action 1')],
...@@ -1680,6 +1723,7 @@ void main() { ...@@ -1680,6 +1723,7 @@ void main() {
home: CustomScrollView( home: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
leading: Text('Leading'), leading: Text('Leading'),
flexibleSpace: Text('Flexible space'), flexibleSpace: Text('Flexible space'),
actions: <Widget>[Text('Action 1')], actions: <Widget>[Text('Action 1')],
...@@ -1753,11 +1797,15 @@ void main() { ...@@ -1753,11 +1797,15 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: darkTheme, theme: darkTheme,
home: Scaffold( home: Scaffold(
appBar: AppBar(title: const Text('test')), appBar: AppBar(
backwardsCompatibility: false,
title: const Text('test')
),
), ),
)); ));
expect(darkTheme.primaryColorBrightness, Brightness.dark); expect(darkTheme.primaryColorBrightness, Brightness.dark);
expect(darkTheme.colorScheme.brightness, Brightness.dark);
expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( expect(SystemChrome.latestStyle, const SystemUiOverlayStyle(
statusBarBrightness: Brightness.dark, statusBarBrightness: Brightness.dark,
statusBarIconBrightness: Brightness.light, statusBarIconBrightness: Brightness.light,
...@@ -1766,14 +1814,20 @@ void main() { ...@@ -1766,14 +1814,20 @@ void main() {
testWidgets('AppBar draws a dark system bar for a light background', (WidgetTester tester) async { testWidgets('AppBar draws a dark system bar for a light background', (WidgetTester tester) async {
final ThemeData lightTheme = ThemeData(primaryColor: Colors.white); final ThemeData lightTheme = ThemeData(primaryColor: Colors.white);
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(
MaterialApp(
theme: lightTheme, theme: lightTheme,
home: Scaffold( home: Scaffold(
appBar: AppBar(title: const Text('test')), appBar: AppBar(
backwardsCompatibility: false,
title: const Text('test')
), ),
)); ),
),
);
expect(lightTheme.primaryColorBrightness, Brightness.light); expect(lightTheme.primaryColorBrightness, Brightness.light);
expect(lightTheme.colorScheme.brightness, Brightness.light);
expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( expect(SystemChrome.latestStyle, const SystemUiOverlayStyle(
statusBarBrightness: Brightness.light, statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark, statusBarIconBrightness: Brightness.dark,
...@@ -1793,6 +1847,7 @@ void main() { ...@@ -1793,6 +1847,7 @@ void main() {
body: CustomScrollView( body: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
expandedHeight: appBarHeight, expandedHeight: appBarHeight,
pinned: false, pinned: false,
floating: true, floating: true,
...@@ -1846,6 +1901,7 @@ void main() { ...@@ -1846,6 +1901,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: AppBar( home: AppBar(
backwardsCompatibility: false,
leading: const Text('L'), leading: const Text('L'),
title: const Text('No Scaffold'), title: const Text('No Scaffold'),
actions: const <Widget>[Text('A1'), Text('A2')], actions: const <Widget>[Text('A1'), Text('A2')],
...@@ -1869,6 +1925,7 @@ void main() { ...@@ -1869,6 +1925,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: AppBar( home: AppBar(
backwardsCompatibility: false,
leading: const Text('L'), leading: const Text('L'),
title: const Text('No Scaffold'), title: const Text('No Scaffold'),
actions: const <Widget>[Text('A1'), Text('A2')], actions: const <Widget>[Text('A1'), Text('A2')],
...@@ -1892,6 +1949,7 @@ void main() { ...@@ -1892,6 +1949,7 @@ void main() {
home: CustomScrollView( home: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
leading: Text('L'), leading: Text('L'),
title: Text('No Scaffold'), title: Text('No Scaffold'),
actions: <Widget>[Text('A1'), Text('A2')], actions: <Widget>[Text('A1'), Text('A2')],
...@@ -1919,6 +1977,7 @@ void main() { ...@@ -1919,6 +1977,7 @@ void main() {
home: CustomScrollView( home: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
leading: Text('L'), leading: Text('L'),
title: Text('No Scaffold'), title: Text('No Scaffold'),
actions: <Widget>[Text('A1'), Text('A2')], actions: <Widget>[Text('A1'), Text('A2')],
...@@ -1949,6 +2008,7 @@ void main() { ...@@ -1949,6 +2008,7 @@ void main() {
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: false, centerTitle: false,
title: const Text('Jumbo', style: TextStyle(fontSize: 18)), title: const Text('Jumbo', style: TextStyle(fontSize: 18)),
), ),
...@@ -1989,6 +2049,7 @@ void main() { ...@@ -1989,6 +2049,7 @@ void main() {
builder: (BuildContext context) { builder: (BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
centerTitle: centerTitle, centerTitle: centerTitle,
title: MediaQuery( title: MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
...@@ -2049,6 +2110,7 @@ void main() { ...@@ -2049,6 +2110,7 @@ void main() {
home: CustomScrollView( home: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
title: const Text('Jumbo'), title: const Text('Jumbo'),
pinned: pinned, pinned: pinned,
floating: floating, floating: floating,
...@@ -2082,6 +2144,7 @@ void main() { ...@@ -2082,6 +2144,7 @@ void main() {
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('Title'), title: const Text('Title'),
toolbarHeight: 48, toolbarHeight: 48,
), ),
...@@ -2140,6 +2203,7 @@ void main() { ...@@ -2140,6 +2203,7 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
leading: const Placeholder(key: key), leading: const Placeholder(key: key),
leadingWidth: 100, leadingWidth: 100,
title: const Text('Title'), title: const Text('Title'),
...@@ -2157,6 +2221,7 @@ void main() { ...@@ -2157,6 +2221,7 @@ void main() {
home: CustomScrollView( home: CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
leading: Placeholder(key: key), leading: Placeholder(key: key),
leadingWidth: 100, leadingWidth: 100,
title: Text('Title'), title: Text('Title'),
......
...@@ -17,6 +17,7 @@ void main() { ...@@ -17,6 +17,7 @@ void main() {
testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async { testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: Scaffold(appBar: AppBar( home: Scaffold(appBar: AppBar(
backwardsCompatibility: false,
actions: <Widget>[ actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { }), IconButton(icon: const Icon(Icons.share), onPressed: () { }),
], ],
...@@ -29,7 +30,7 @@ void main() { ...@@ -29,7 +30,7 @@ void main() {
final RichText actionIconText = _getAppBarIconRichText(tester); final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.dark); expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.dark.statusBarBrightness);
expect(widget.color, Colors.blue); expect(widget.color, Colors.blue);
expect(widget.elevation, 4.0); expect(widget.elevation, 4.0);
expect(widget.shadowColor, Colors.black); expect(widget.shadowColor, Colors.black);
...@@ -45,6 +46,7 @@ void main() { ...@@ -45,6 +46,7 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(appBarTheme: appBarTheme), theme: ThemeData(appBarTheme: appBarTheme),
home: Scaffold(appBar: AppBar( home: Scaffold(appBar: AppBar(
backwardsCompatibility: false,
title: const Text('App Bar Title'), title: const Text('App Bar Title'),
actions: <Widget>[ actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { }), IconButton(icon: const Icon(Icons.share), onPressed: () { }),
...@@ -59,41 +61,48 @@ void main() { ...@@ -59,41 +61,48 @@ void main() {
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle!.statusBarBrightness, appBarTheme.brightness); expect(SystemChrome.latestStyle!.statusBarBrightness, appBarTheme.brightness);
expect(widget.color, appBarTheme.color); expect(widget.color, appBarTheme.backgroundColor);
expect(widget.elevation, appBarTheme.elevation); expect(widget.elevation, appBarTheme.elevation);
expect(widget.shadowColor, appBarTheme.shadowColor); expect(widget.shadowColor, appBarTheme.shadowColor);
expect(iconTheme.data, appBarTheme.iconTheme); expect(iconTheme.data, appBarTheme.iconTheme);
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme); expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color); expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color);
expect(text.style, appBarTheme.textTheme!.bodyText2); expect(text.style, appBarTheme.toolbarTextStyle);
}); });
testWidgets('AppBar widget properties take priority over theme', (WidgetTester tester) async { testWidgets('AppBar widget properties take priority over theme', (WidgetTester tester) async {
const Brightness brightness = Brightness.dark; const Brightness brightness = Brightness.dark;
const SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.light;
const Color color = Colors.orange; const Color color = Colors.orange;
const double elevation = 3.0; const double elevation = 3.0;
const Color shadowColor = Colors.red; const Color shadowColor = Colors.red;
const IconThemeData iconThemeData = IconThemeData(color: Colors.green); const IconThemeData iconThemeData = IconThemeData(color: Colors.green);
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue); const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue);
const TextTheme textTheme = TextTheme(headline6: TextStyle(color: Colors.orange), bodyText2: TextStyle(color: Colors.pink)); const TextStyle toolbarTextStyle = TextStyle(color: Colors.pink);
const TextStyle titleTextStyle = TextStyle(color: Colors.orange);
final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme()); await tester.pumpWidget(
MaterialApp(
await tester.pumpWidget(MaterialApp( theme: ThemeData.from(colorScheme: const ColorScheme.light()),
theme: themeData, home: Scaffold(
home: Scaffold(appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
backgroundColor: color, backgroundColor: color,
brightness: brightness, brightness: brightness,
systemOverlayStyle: systemOverlayStyle,
elevation: elevation, elevation: elevation,
shadowColor: shadowColor, shadowColor: shadowColor,
iconTheme: iconThemeData, iconTheme: iconThemeData,
actionsIconTheme: actionsIconThemeData, actionsIconTheme: actionsIconThemeData,
textTheme: textTheme, toolbarTextStyle: toolbarTextStyle,
titleTextStyle: titleTextStyle,
actions: <Widget>[ actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { }), IconButton(icon: const Icon(Icons.share), onPressed: () { }),
], ],
)), ),
)); ),
),
);
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
...@@ -108,7 +117,7 @@ void main() { ...@@ -108,7 +117,7 @@ void main() {
expect(iconTheme.data, iconThemeData); expect(iconTheme.data, iconThemeData);
expect(actionsIconTheme.data, actionsIconThemeData); expect(actionsIconTheme.data, actionsIconThemeData);
expect(actionIconText.text.style!.color, actionsIconThemeData.color); expect(actionIconText.text.style!.color, actionsIconThemeData.color);
expect(text.style, textTheme.bodyText2); expect(text.style, toolbarTextStyle);
}); });
testWidgets('AppBar icon color takes priority over everything', (WidgetTester tester) async { testWidgets('AppBar icon color takes priority over everything', (WidgetTester tester) async {
...@@ -116,11 +125,10 @@ void main() { ...@@ -116,11 +125,10 @@ void main() {
const IconThemeData iconThemeData = IconThemeData(color: Colors.green); const IconThemeData iconThemeData = IconThemeData(color: Colors.green);
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue); const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue);
final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme());
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: themeData, theme: ThemeData.from(colorScheme: const ColorScheme.light()),
home: Scaffold(appBar: AppBar( home: Scaffold(appBar: AppBar(
backwardsCompatibility: false,
iconTheme: iconThemeData, iconTheme: iconThemeData,
actionsIconTheme: actionsIconThemeData, actionsIconTheme: actionsIconThemeData,
actions: <Widget>[ actions: <Widget>[
...@@ -135,16 +143,21 @@ void main() { ...@@ -135,16 +143,21 @@ void main() {
testWidgets('AppBarTheme properties take priority over ThemeData properties', (WidgetTester tester) async { testWidgets('AppBarTheme properties take priority over ThemeData properties', (WidgetTester tester) async {
final AppBarTheme appBarTheme = _appBarTheme(); final AppBarTheme appBarTheme = _appBarTheme();
final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme());
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(
theme: themeData, MaterialApp(
home: Scaffold(appBar: AppBar( theme: ThemeData.from(colorScheme: const ColorScheme.light())
.copyWith(appBarTheme: _appBarTheme()),
home: Scaffold(
appBar: AppBar(
backwardsCompatibility: false,
actions: <Widget>[ actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { }), IconButton(icon: const Icon(Icons.share), onPressed: () { }),
], ],
)), ),
)); ),
),
);
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
...@@ -153,26 +166,47 @@ void main() { ...@@ -153,26 +166,47 @@ void main() {
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle!.statusBarBrightness, appBarTheme.brightness); expect(SystemChrome.latestStyle!.statusBarBrightness, appBarTheme.brightness);
expect(widget.color, appBarTheme.color); expect(widget.color, appBarTheme.backgroundColor);
expect(widget.elevation, appBarTheme.elevation); expect(widget.elevation, appBarTheme.elevation);
expect(widget.shadowColor, appBarTheme.shadowColor); expect(widget.shadowColor, appBarTheme.shadowColor);
expect(iconTheme.data, appBarTheme.iconTheme); expect(iconTheme.data, appBarTheme.iconTheme);
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme); expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color); expect(actionIconText.text.style!.color, appBarTheme.actionsIconTheme!.color);
expect(text.style, appBarTheme.textTheme!.bodyText2); expect(text.style, appBarTheme.toolbarTextStyle);
}); });
testWidgets('ThemeData properties are used when no AppBarTheme is set', (WidgetTester tester) async { testWidgets('ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async {
final ThemeData themeData = _themeData(); late ThemeData theme;
Widget buildFrame(ThemeData appTheme) {
await tester.pumpWidget(MaterialApp( return MaterialApp(
theme: themeData, theme: appTheme,
home: Scaffold(appBar: AppBar( home: Builder(
builder: (BuildContext context) {
// This ThemeData has been localized with ThemeData.localize. The
// appTheme parameter has not, so its textTheme is incomplete.
theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
backwardsCompatibility: false,
actions: <Widget>[ actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { }), IconButton(icon: const Icon(Icons.share), onPressed: () { }),
], ],
)), ),
)); );
},
),
);
}
// AppBar defaults for light themes:
// - elevation: 4
// - shadow color: black
// - background color: ColorScheme.primary
// - foreground color: ColorScheme.onPrimary
// - actions text: style bodyText2, foreground color
// - status bar brightness: dark (based on color scheme brightness)
{
await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.light())));
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
...@@ -180,21 +214,92 @@ void main() { ...@@ -180,21 +214,92 @@ void main() {
final RichText actionIconText = _getAppBarIconRichText(tester); final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle!.statusBarBrightness, themeData.brightness); expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.dark.statusBarBrightness);
expect(widget.color, themeData.primaryColor); expect(widget.color, theme.colorScheme.primary);
expect(widget.elevation, 4.0); expect(widget.elevation, 4.0);
expect(widget.shadowColor, Colors.black); expect(widget.shadowColor, Colors.black);
expect(iconTheme.data, themeData.primaryIconTheme); expect(iconTheme.data.color, theme.colorScheme.onPrimary);
expect(actionsIconTheme.data, themeData.primaryIconTheme); expect(actionsIconTheme.data.color, theme.colorScheme.onPrimary);
expect(actionIconText.text.style!.color, themeData.primaryIconTheme.color); expect(actionIconText.text.style!.color, theme.colorScheme.onPrimary);
// Default value for ThemeData.typography is Typography.material2014() expect(text.style.compareTo(theme.textTheme.bodyText2!.copyWith(color: theme.colorScheme.onPrimary)), RenderComparison.identical);
expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().white.bodyText2).merge(themeData.primaryTextTheme.bodyText2)); }
// AppBar defaults for dark themes:
// - elevation: 4
// - shadow color: black
// - background color: ColorScheme.surface
// - foreground color: ColorScheme.onSurface
// - actions text: style bodyText2, foreground color
// - status bar brightness: dark (based on background color)
{
await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.dark())));
await tester.pumpAndSettle(); // Theme change animation
final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness);
expect(widget.color, theme.colorScheme.surface);
expect(widget.elevation, 4.0);
expect(widget.shadowColor, Colors.black);
expect(iconTheme.data.color, theme.colorScheme.onSurface);
expect(actionsIconTheme.data.color, theme.colorScheme.onSurface);
expect(actionIconText.text.style!.color, theme.colorScheme.onSurface);
expect(text.style.compareTo(theme.textTheme.bodyText2!.copyWith(color: theme.colorScheme.onSurface)), RenderComparison.identical);
}
});
testWidgets('AppBar iconTheme with color=null defers to outer IconTheme', (WidgetTester tester) async {
// Verify claim made in https://github.com/flutter/flutter/pull/71184#issuecomment-737419215
Widget buildFrame({ Color? appIconColor, Color? appBarIconColor }) {
return MaterialApp(
theme: ThemeData.from(colorScheme: const ColorScheme.light()),
home: IconTheme(
data: IconThemeData(color: appIconColor),
child: Builder(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
backwardsCompatibility: false,
iconTheme: IconThemeData(color: appBarIconColor),
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () { })
],
),
);
},
),
),
);
}
RichText getIconText() {
return tester.widget<RichText>(
find.descendant(
of: find.byType(Icon),
matching: find.byType(RichText),
),
);
}
await tester.pumpWidget(buildFrame(appIconColor: Colors.lime, appBarIconColor: null));
expect(getIconText().text.style!.color, Colors.lime);
await tester.pumpWidget(buildFrame(appIconColor: Colors.lime, appBarIconColor: Colors.purple));
expect(getIconText().text.style!.color, Colors.purple);
}); });
testWidgets('AppBar uses AppBarTheme.centerTitle when centerTitle is null', (WidgetTester tester) async { testWidgets('AppBar uses AppBarTheme.centerTitle when centerTitle is null', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(appBarTheme: const AppBarTheme(centerTitle: true)), theme: ThemeData(appBarTheme: const AppBarTheme(centerTitle: true)),
home: Scaffold(appBar: AppBar(title: const Text('Title'))), home: Scaffold(appBar: AppBar(
title: const Text('Title'),
backwardsCompatibility: false,
)),
)); ));
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
...@@ -206,6 +311,7 @@ void main() { ...@@ -206,6 +311,7 @@ void main() {
theme: ThemeData(appBarTheme: const AppBarTheme(centerTitle: true)), theme: ThemeData(appBarTheme: const AppBarTheme(centerTitle: true)),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('Title'), title: const Text('Title'),
centerTitle: false, centerTitle: false,
), ),
...@@ -220,7 +326,10 @@ void main() { ...@@ -220,7 +326,10 @@ void main() {
testWidgets('AppBar.centerTitle adapts to TargetPlatform when AppBarTheme.centerTitle is null', (WidgetTester tester) async{ testWidgets('AppBar.centerTitle adapts to TargetPlatform when AppBarTheme.centerTitle is null', (WidgetTester tester) async{
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS), theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(appBar: AppBar(title: const Text('Title'))), home: Scaffold(appBar: AppBar(
backwardsCompatibility: false,
title: const Text('Title')
)),
)); ));
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
...@@ -234,6 +343,7 @@ void main() { ...@@ -234,6 +343,7 @@ void main() {
theme: ThemeData(appBarTheme: const AppBarTheme(shadowColor: Colors.red)), theme: ThemeData(appBarTheme: const AppBarTheme(shadowColor: Colors.red)),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('Title'), title: const Text('Title'),
shadowColor: Colors.yellow, shadowColor: Colors.yellow,
), ),
...@@ -251,6 +361,7 @@ void main() { ...@@ -251,6 +361,7 @@ void main() {
theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)), theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('Title'), title: const Text('Title'),
), ),
), ),
...@@ -266,6 +377,7 @@ void main() { ...@@ -266,6 +377,7 @@ void main() {
theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)), theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)),
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(
backwardsCompatibility: false,
title: const Text('Title'), title: const Text('Title'),
titleSpacing: 40, titleSpacing: 40,
), ),
...@@ -283,6 +395,7 @@ void main() { ...@@ -283,6 +395,7 @@ void main() {
home: const CustomScrollView( home: const CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
title: Text('Title'), title: Text('Title'),
), ),
], ],
...@@ -300,6 +413,7 @@ void main() { ...@@ -300,6 +413,7 @@ void main() {
home: const CustomScrollView( home: const CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
SliverAppBar( SliverAppBar(
backwardsCompatibility: false,
title: Text('Title'), title: Text('Title'),
titleSpacing: 40, titleSpacing: 40,
), ),
...@@ -358,29 +472,20 @@ void main() { ...@@ -358,29 +472,20 @@ void main() {
AppBarTheme _appBarTheme() { AppBarTheme _appBarTheme() {
const Brightness brightness = Brightness.light; const Brightness brightness = Brightness.light;
const Color color = Colors.lightBlue; const Color backgroundColor = Colors.lightBlue;
const double elevation = 6.0; const double elevation = 6.0;
const Color shadowColor = Colors.red; const Color shadowColor = Colors.red;
const IconThemeData iconThemeData = IconThemeData(color: Colors.black); const IconThemeData iconThemeData = IconThemeData(color: Colors.black);
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.pink); const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.pink);
const TextTheme textTheme = TextTheme(bodyText2: TextStyle(color: Colors.yellow));
return const AppBarTheme( return const AppBarTheme(
actionsIconTheme: actionsIconThemeData, actionsIconTheme: actionsIconThemeData,
brightness: brightness, brightness: brightness,
color: color, backgroundColor: backgroundColor,
elevation: elevation, elevation: elevation,
shadowColor: shadowColor, shadowColor: shadowColor,
iconTheme: iconThemeData, iconTheme: iconThemeData,
textTheme: textTheme, toolbarTextStyle: TextStyle(color: Colors.yellow),
); titleTextStyle: TextStyle(color: Colors.pink),
}
ThemeData _themeData() {
return ThemeData(
primaryColor: Colors.purple,
brightness: Brightness.dark,
primaryIconTheme: const IconThemeData(color: Colors.green),
primaryTextTheme: const TextTheme(headline6: TextStyle(color: Colors.orange), bodyText2: 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