mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Add shadowColor to AppBar and AppBarTheme (#58708)
This commit is contained in:
parent
6202476691
commit
d9bf8794c2
|
@ -175,7 +175,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
|||
/// and [automaticallyImplyLeading] must not be null. Additionally, if
|
||||
/// [elevation] is specified, it must be non-negative.
|
||||
///
|
||||
/// If [backgroundColor], [elevation], [brightness], [iconTheme],
|
||||
/// 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.
|
||||
|
@ -190,6 +190,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
|||
this.flexibleSpace,
|
||||
this.bottom,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.shape,
|
||||
this.backgroundColor,
|
||||
this.brightness,
|
||||
|
@ -338,6 +339,13 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
|||
/// for app bars.
|
||||
final double elevation;
|
||||
|
||||
/// The color to paint the shadow below the app bar.
|
||||
///
|
||||
/// If this property is null, then [ThemeData.appBarTheme.shadowColor] is used,
|
||||
/// if that is also null, the default value is fully opaque black, the appropriate
|
||||
/// color for shadows.
|
||||
final Color shadowColor;
|
||||
|
||||
/// The material's shape as well its shadow.
|
||||
///
|
||||
/// A shadow is only displayed if the [elevation] is greater than
|
||||
|
@ -456,6 +464,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
|||
|
||||
class _AppBarState extends State<AppBar> {
|
||||
static const double _defaultElevation = 4.0;
|
||||
static const Color _defaultShadowColor = Color(0xFF000000);
|
||||
|
||||
void _handleDrawerButton() {
|
||||
Scaffold.of(context).openDrawer();
|
||||
|
@ -665,6 +674,9 @@ class _AppBarState extends State<AppBar> {
|
|||
elevation: widget.elevation
|
||||
?? appBarTheme.elevation
|
||||
?? _defaultElevation,
|
||||
shadowColor: widget.shadowColor
|
||||
?? appBarTheme.shadowColor
|
||||
?? _defaultShadowColor,
|
||||
shape: widget.shape,
|
||||
child: Semantics(
|
||||
explicitChildNodes: true,
|
||||
|
@ -737,6 +749,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
@required this.flexibleSpace,
|
||||
@required this.bottom,
|
||||
@required this.elevation,
|
||||
@required this.shadowColor,
|
||||
@required this.forceElevated,
|
||||
@required this.backgroundColor,
|
||||
@required this.brightness,
|
||||
|
@ -765,6 +778,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
final Widget flexibleSpace;
|
||||
final PreferredSizeWidget bottom;
|
||||
final double elevation;
|
||||
final Color shadowColor;
|
||||
final bool forceElevated;
|
||||
final Color backgroundColor;
|
||||
final Brightness brightness;
|
||||
|
@ -822,6 +836,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
: flexibleSpace,
|
||||
bottom: bottom,
|
||||
elevation: forceElevated || overlapsContent || (pinned && shrinkOffset > maxExtent - minExtent) ? elevation ?? 4.0 : 0.0,
|
||||
shadowColor: shadowColor,
|
||||
backgroundColor: backgroundColor,
|
||||
brightness: brightness,
|
||||
iconTheme: iconTheme,
|
||||
|
@ -849,6 +864,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
|| bottom != oldDelegate.bottom
|
||||
|| _bottomHeight != oldDelegate._bottomHeight
|
||||
|| elevation != oldDelegate.elevation
|
||||
|| shadowColor != oldDelegate.shadowColor
|
||||
|| backgroundColor != oldDelegate.backgroundColor
|
||||
|| brightness != oldDelegate.brightness
|
||||
|| iconTheme != oldDelegate.iconTheme
|
||||
|
@ -964,6 +980,7 @@ class SliverAppBar extends StatefulWidget {
|
|||
this.flexibleSpace,
|
||||
this.bottom,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.forceElevated = false,
|
||||
this.backgroundColor,
|
||||
this.brightness,
|
||||
|
@ -1081,6 +1098,14 @@ class SliverAppBar extends StatefulWidget {
|
|||
/// shadow is drawn, regardless of the value of [elevation].
|
||||
final double elevation;
|
||||
|
||||
/// The color to paint the shadow below the app bar. Typically this should be set
|
||||
/// along with [elevation].
|
||||
///
|
||||
/// If this property is null, then [ThemeData.appBarTheme.shadowColor] is used,
|
||||
/// if that is also null, the default value is fully opaque black, the appropriate
|
||||
/// color for shadows.
|
||||
final Color shadowColor;
|
||||
|
||||
/// Whether to show the shadow appropriate for the [elevation] even if the
|
||||
/// content is not scrolled under the [AppBar].
|
||||
///
|
||||
|
@ -1339,6 +1364,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
|
|||
flexibleSpace: widget.flexibleSpace,
|
||||
bottom: widget.bottom,
|
||||
elevation: widget.elevation,
|
||||
shadowColor: widget.shadowColor,
|
||||
forceElevated: widget.forceElevated,
|
||||
backgroundColor: widget.backgroundColor,
|
||||
brightness: widget.brightness,
|
||||
|
|
|
@ -36,6 +36,7 @@ class AppBarTheme with Diagnosticable {
|
|||
this.brightness,
|
||||
this.color,
|
||||
this.elevation,
|
||||
this.shadowColor,
|
||||
this.iconTheme,
|
||||
this.actionsIconTheme,
|
||||
this.textTheme,
|
||||
|
@ -57,6 +58,11 @@ class AppBarTheme with Diagnosticable {
|
|||
/// If null, [AppBar] uses a default value of 4.0.
|
||||
final double elevation;
|
||||
|
||||
/// Default value for [AppBar.shadowColor].
|
||||
///
|
||||
/// If null, [AppBar] uses a default value of fully opaque black.
|
||||
final Color shadowColor;
|
||||
|
||||
/// Default value for [AppBar.iconTheme].
|
||||
///
|
||||
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
|
||||
|
@ -84,6 +90,7 @@ class AppBarTheme with Diagnosticable {
|
|||
Brightness brightness,
|
||||
Color color,
|
||||
double elevation,
|
||||
Color shadowColor,
|
||||
IconThemeData iconTheme,
|
||||
TextTheme textTheme,
|
||||
bool centerTitle,
|
||||
|
@ -92,6 +99,7 @@ class AppBarTheme with Diagnosticable {
|
|||
brightness: brightness ?? this.brightness,
|
||||
color: color ?? this.color,
|
||||
elevation: elevation ?? this.elevation,
|
||||
shadowColor: shadowColor ?? this.shadowColor,
|
||||
iconTheme: iconTheme ?? this.iconTheme,
|
||||
actionsIconTheme: actionsIconTheme ?? this.actionsIconTheme,
|
||||
textTheme: textTheme ?? this.textTheme,
|
||||
|
@ -115,6 +123,7 @@ class AppBarTheme with Diagnosticable {
|
|||
brightness: t < 0.5 ? a?.brightness : b?.brightness,
|
||||
color: Color.lerp(a?.color, b?.color, t),
|
||||
elevation: lerpDouble(a?.elevation, b?.elevation, t),
|
||||
shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
|
||||
iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t),
|
||||
actionsIconTheme: IconThemeData.lerp(a?.actionsIconTheme, b?.actionsIconTheme, t),
|
||||
textTheme: TextTheme.lerp(a?.textTheme, b?.textTheme, t),
|
||||
|
@ -128,6 +137,7 @@ class AppBarTheme with Diagnosticable {
|
|||
brightness,
|
||||
color,
|
||||
elevation,
|
||||
shadowColor,
|
||||
iconTheme,
|
||||
actionsIconTheme,
|
||||
textTheme,
|
||||
|
@ -145,6 +155,7 @@ class AppBarTheme with Diagnosticable {
|
|||
&& other.brightness == brightness
|
||||
&& other.color == color
|
||||
&& other.elevation == elevation
|
||||
&& other.shadowColor == shadowColor
|
||||
&& other.iconTheme == iconTheme
|
||||
&& other.actionsIconTheme == actionsIconTheme
|
||||
&& other.textTheme == textTheme
|
||||
|
@ -157,6 +168,7 @@ class AppBarTheme with Diagnosticable {
|
|||
properties.add(DiagnosticsProperty<Brightness>('brightness', brightness, defaultValue: null));
|
||||
properties.add(ColorProperty('color', color, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null));
|
||||
properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<IconThemeData>('iconTheme', iconTheme, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<IconThemeData>('actionsIconTheme', actionsIconTheme, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<TextTheme>('textTheme', textTheme, defaultValue: null));
|
||||
|
|
|
@ -33,6 +33,7 @@ void main() {
|
|||
expect(SystemChrome.latestStyle.statusBarBrightness, Brightness.dark);
|
||||
expect(widget.color, Colors.blue);
|
||||
expect(widget.elevation, 4.0);
|
||||
expect(widget.shadowColor, Colors.black);
|
||||
expect(iconTheme.data, const IconThemeData(color: Colors.white));
|
||||
expect(actionsIconTheme.data, const IconThemeData(color: Colors.white));
|
||||
expect(actionIconText.text.style.color, Colors.white);
|
||||
|
@ -61,6 +62,7 @@ void main() {
|
|||
expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness);
|
||||
expect(widget.color, appBarTheme.color);
|
||||
expect(widget.elevation, appBarTheme.elevation);
|
||||
expect(widget.shadowColor, appBarTheme.shadowColor);
|
||||
expect(iconTheme.data, appBarTheme.iconTheme);
|
||||
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
|
||||
expect(actionIconText.text.style.color, appBarTheme.actionsIconTheme.color);
|
||||
|
@ -71,6 +73,7 @@ void main() {
|
|||
const Brightness brightness = Brightness.dark;
|
||||
const Color color = Colors.orange;
|
||||
const double elevation = 3.0;
|
||||
const Color shadowColor = Colors.red;
|
||||
const IconThemeData iconThemeData = IconThemeData(color: Colors.green);
|
||||
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue);
|
||||
const TextTheme textTheme = TextTheme(headline6: TextStyle(color: Colors.orange), bodyText2: TextStyle(color: Colors.pink));
|
||||
|
@ -83,6 +86,7 @@ void main() {
|
|||
backgroundColor: color,
|
||||
brightness: brightness,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
iconTheme: iconThemeData,
|
||||
actionsIconTheme: actionsIconThemeData,
|
||||
textTheme: textTheme,
|
||||
|
@ -101,6 +105,7 @@ void main() {
|
|||
expect(SystemChrome.latestStyle.statusBarBrightness, brightness);
|
||||
expect(widget.color, color);
|
||||
expect(widget.elevation, elevation);
|
||||
expect(widget.shadowColor, shadowColor);
|
||||
expect(iconTheme.data, iconThemeData);
|
||||
expect(actionsIconTheme.data, actionsIconThemeData);
|
||||
expect(actionIconText.text.style.color, actionsIconThemeData.color);
|
||||
|
@ -151,6 +156,7 @@ void main() {
|
|||
expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness);
|
||||
expect(widget.color, appBarTheme.color);
|
||||
expect(widget.elevation, appBarTheme.elevation);
|
||||
expect(widget.shadowColor, appBarTheme.shadowColor);
|
||||
expect(iconTheme.data, appBarTheme.iconTheme);
|
||||
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
|
||||
expect(actionIconText.text.style.color, appBarTheme.actionsIconTheme.color);
|
||||
|
@ -178,6 +184,7 @@ void main() {
|
|||
expect(SystemChrome.latestStyle.statusBarBrightness, themeData.brightness);
|
||||
expect(widget.color, themeData.primaryColor);
|
||||
expect(widget.elevation, 4.0);
|
||||
expect(widget.shadowColor, Colors.black);
|
||||
expect(iconTheme.data, themeData.primaryIconTheme);
|
||||
expect(actionsIconTheme.data, themeData.primaryIconTheme);
|
||||
expect(actionIconText.text.style.color, themeData.primaryIconTheme.color);
|
||||
|
@ -199,10 +206,11 @@ void main() {
|
|||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(appBarTheme: const AppBarTheme(centerTitle: true)),
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Title'),
|
||||
centerTitle: false,
|
||||
)),
|
||||
appBar: AppBar(
|
||||
title: const Text('Title'),
|
||||
centerTitle: false,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar));
|
||||
|
@ -221,12 +229,29 @@ void main() {
|
|||
// the value of NavigationToolBar.centerMiddle should be true.
|
||||
expect(navToolBar.centerMiddle, true);
|
||||
});
|
||||
|
||||
testWidgets('AppBar.shadowColor takes priority over AppBarTheme.shadowColor', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(appBarTheme: const AppBarTheme(shadowColor: Colors.red)),
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Title'),
|
||||
shadowColor: Colors.yellow,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final AppBar appBar = tester.widget(find.byType(AppBar));
|
||||
// The AppBar.shadowColor should be used instead of AppBarTheme.shadowColor.
|
||||
expect(appBar.shadowColor, Colors.yellow);
|
||||
});
|
||||
}
|
||||
|
||||
AppBarTheme _appBarTheme() {
|
||||
const Brightness brightness = Brightness.light;
|
||||
const Color color = Colors.lightBlue;
|
||||
const double elevation = 6.0;
|
||||
const Color shadowColor = Colors.red;
|
||||
const IconThemeData iconThemeData = IconThemeData(color: Colors.black);
|
||||
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.pink);
|
||||
const TextTheme textTheme = TextTheme(bodyText2: TextStyle(color: Colors.yellow));
|
||||
|
@ -235,6 +260,7 @@ AppBarTheme _appBarTheme() {
|
|||
brightness: brightness,
|
||||
color: color,
|
||||
elevation: elevation,
|
||||
shadowColor: shadowColor,
|
||||
iconTheme: iconThemeData,
|
||||
textTheme: textTheme,
|
||||
);
|
||||
|
@ -284,6 +310,7 @@ RichText _getAppBarIconRichText(WidgetTester tester) {
|
|||
).first,
|
||||
);
|
||||
}
|
||||
|
||||
DefaultTextStyle _getAppBarText(WidgetTester tester) {
|
||||
return tester.widget<DefaultTextStyle>(
|
||||
find.descendant(
|
||||
|
|
Loading…
Reference in a new issue