Unverified Commit 0082ff97 authored by Aayan's avatar Aayan Committed by GitHub

Material banner updates (#90380)

parent 92a55d0a
...@@ -6,12 +6,12 @@ import 'package:flutter/widgets.dart'; ...@@ -6,12 +6,12 @@ import 'package:flutter/widgets.dart';
import 'banner_theme.dart'; import 'banner_theme.dart';
import 'divider.dart'; import 'divider.dart';
import 'material.dart';
import 'scaffold.dart'; import 'scaffold.dart';
import 'theme.dart'; import 'theme.dart';
const Duration _materialBannerTransitionDuration = Duration(milliseconds: 250); const Duration _materialBannerTransitionDuration = Duration(milliseconds: 250);
const Curve _materialBannerHeightCurve = Curves.fastOutSlowIn; const Curve _materialBannerHeightCurve = Curves.fastOutSlowIn;
const Curve _materialBannerFadeOutCurve = Interval(0.72, 1.0, curve: Curves.fastOutSlowIn);
/// Specify how a [MaterialBanner] was closed. /// Specify how a [MaterialBanner] was closed.
/// ///
...@@ -84,12 +84,14 @@ class MaterialBanner extends StatefulWidget { ...@@ -84,12 +84,14 @@ class MaterialBanner extends StatefulWidget {
/// Creates a [MaterialBanner]. /// Creates a [MaterialBanner].
/// ///
/// The [actions], [content], and [forceActionsBelow] must be non-null. /// The [actions], [content], and [forceActionsBelow] must be non-null.
/// The [actions].length must be greater than 0. /// The [actions].length must be greater than 0. The [elevation] must be null or
/// non-negative.
const MaterialBanner({ const MaterialBanner({
Key? key, Key? key,
required this.content, required this.content,
this.contentTextStyle, this.contentTextStyle,
required this.actions, required this.actions,
this.elevation,
this.leading, this.leading,
this.backgroundColor, this.backgroundColor,
this.padding, this.padding,
...@@ -98,7 +100,8 @@ class MaterialBanner extends StatefulWidget { ...@@ -98,7 +100,8 @@ class MaterialBanner extends StatefulWidget {
this.overflowAlignment = OverflowBarAlignment.end, this.overflowAlignment = OverflowBarAlignment.end,
this.animation, this.animation,
this.onVisible this.onVisible
}) : assert(content != null), }) : assert(elevation == null || elevation >= 0.0),
assert(content != null),
assert(actions != null), assert(actions != null),
assert(forceActionsBelow != null), assert(forceActionsBelow != null),
super(key: key); super(key: key);
...@@ -120,6 +123,18 @@ class MaterialBanner extends StatefulWidget { ...@@ -120,6 +123,18 @@ class MaterialBanner extends StatefulWidget {
/// Typically this is a list of [TextButton] widgets. /// Typically this is a list of [TextButton] widgets.
final List<Widget> actions; final List<Widget> actions;
/// The z-coordinate at which to place the material banner.
///
/// This controls the size of the shadow below the material banner.
///
/// Defines the banner's [Material.elevation].
///
/// If this property is null, then [MaterialBannerThemeData.elevation] of
/// [ThemeData.bannerTheme] is used, if that is also null, the default value is 0.
/// If the elevation is 0, the [Scaffold]'s body will be pushed down by the
/// MaterialBanner when used with [ScaffoldMessenger].
final double? elevation;
/// The (optional) leading widget of the [MaterialBanner]. /// The (optional) leading widget of the [MaterialBanner].
/// ///
/// Typically an [Icon] widget. /// Typically an [Icon] widget.
...@@ -188,6 +203,7 @@ class MaterialBanner extends StatefulWidget { ...@@ -188,6 +203,7 @@ class MaterialBanner extends StatefulWidget {
content: content, content: content,
contentTextStyle: contentTextStyle, contentTextStyle: contentTextStyle,
actions: actions, actions: actions,
elevation: elevation,
leading: leading, leading: leading,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
padding: padding, padding: padding,
...@@ -270,6 +286,7 @@ class _MaterialBannerState extends State<MaterialBanner> { ...@@ -270,6 +286,7 @@ class _MaterialBannerState extends State<MaterialBanner> {
), ),
); );
final double elevation = widget.elevation ?? bannerTheme.elevation ?? 0.0;
final Color backgroundColor = widget.backgroundColor final Color backgroundColor = widget.backgroundColor
?? bannerTheme.backgroundColor ?? bannerTheme.backgroundColor
?? theme.colorScheme.surface; ?? theme.colorScheme.surface;
...@@ -278,34 +295,40 @@ class _MaterialBannerState extends State<MaterialBanner> { ...@@ -278,34 +295,40 @@ class _MaterialBannerState extends State<MaterialBanner> {
?? theme.textTheme.bodyText2; ?? theme.textTheme.bodyText2;
Widget materialBanner = Container( Widget materialBanner = Container(
color: backgroundColor, margin: EdgeInsets.only(bottom: elevation > 0 ? 10.0 : 0.0),
child: Column( child: Material(
mainAxisSize: MainAxisSize.min, elevation: elevation,
children: <Widget>[ color: backgroundColor,
Padding( child: Column(
padding: padding, mainAxisSize: MainAxisSize.min,
child: Row( children: <Widget>[
children: <Widget>[ Padding(
if (widget.leading != null) padding: padding,
Padding( child: Row(
padding: leadingPadding, children: <Widget>[
child: widget.leading, if (widget.leading != null)
), Padding(
Expanded( padding: leadingPadding,
child: DefaultTextStyle( child: widget.leading,
style: textStyle!, ),
child: widget.content, Expanded(
child: DefaultTextStyle(
style: textStyle!,
child: widget.content,
),
), ),
), if (isSingleRow)
if (isSingleRow) buttonBar,
buttonBar, ],
], ),
), ),
), if (!isSingleRow)
if (!isSingleRow) buttonBar,
buttonBar,
const Divider(height: 0), if (elevation == 0)
], const Divider(height: 0),
],
),
), ),
); );
...@@ -313,12 +336,19 @@ class _MaterialBannerState extends State<MaterialBanner> { ...@@ -313,12 +336,19 @@ class _MaterialBannerState extends State<MaterialBanner> {
if (widget.animation == null) if (widget.animation == null)
return materialBanner; return materialBanner;
materialBanner = SafeArea(
top: true,
child: materialBanner,
);
final CurvedAnimation heightAnimation = CurvedAnimation(parent: widget.animation!, curve: _materialBannerHeightCurve); final CurvedAnimation heightAnimation = CurvedAnimation(parent: widget.animation!, curve: _materialBannerHeightCurve);
final CurvedAnimation fadeOutAnimation = CurvedAnimation( final Animation<Offset> slideOutAnimation = Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: widget.animation!, parent: widget.animation!,
curve: _materialBannerFadeOutCurve, curve: const Threshold(0.0),
reverseCurve: const Threshold(0.0), ));
);
materialBanner = Semantics( materialBanner = Semantics(
container: true, container: true,
...@@ -328,8 +358,8 @@ class _MaterialBannerState extends State<MaterialBanner> { ...@@ -328,8 +358,8 @@ class _MaterialBannerState extends State<MaterialBanner> {
}, },
child: mediaQueryData.accessibleNavigation child: mediaQueryData.accessibleNavigation
? materialBanner ? materialBanner
: FadeTransition( : SlideTransition(
opacity: fadeOutAnimation, position: slideOutAnimation,
child: materialBanner, child: materialBanner,
), ),
); );
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ui' show lerpDouble;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -31,6 +33,7 @@ class MaterialBannerThemeData with Diagnosticable { ...@@ -31,6 +33,7 @@ class MaterialBannerThemeData with Diagnosticable {
const MaterialBannerThemeData({ const MaterialBannerThemeData({
this.backgroundColor, this.backgroundColor,
this.contentTextStyle, this.contentTextStyle,
this.elevation,
this.padding, this.padding,
this.leadingPadding, this.leadingPadding,
}); });
...@@ -42,6 +45,11 @@ class MaterialBannerThemeData with Diagnosticable { ...@@ -42,6 +45,11 @@ class MaterialBannerThemeData with Diagnosticable {
/// widget. /// widget.
final TextStyle? contentTextStyle; final TextStyle? contentTextStyle;
/// Default value for [MaterialBanner.elevation].
//
// If null, MaterialBanner uses a default of 0.0.
final double? elevation;
/// The amount of space by which to inset [MaterialBanner.content]. /// The amount of space by which to inset [MaterialBanner.content].
final EdgeInsetsGeometry? padding; final EdgeInsetsGeometry? padding;
...@@ -53,12 +61,14 @@ class MaterialBannerThemeData with Diagnosticable { ...@@ -53,12 +61,14 @@ class MaterialBannerThemeData with Diagnosticable {
MaterialBannerThemeData copyWith({ MaterialBannerThemeData copyWith({
Color? backgroundColor, Color? backgroundColor,
TextStyle? contentTextStyle, TextStyle? contentTextStyle,
double? elevation,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
EdgeInsetsGeometry? leadingPadding, EdgeInsetsGeometry? leadingPadding,
}) { }) {
return MaterialBannerThemeData( return MaterialBannerThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor, backgroundColor: backgroundColor ?? this.backgroundColor,
contentTextStyle: contentTextStyle ?? this.contentTextStyle, contentTextStyle: contentTextStyle ?? this.contentTextStyle,
elevation: elevation ?? this.elevation,
padding: padding ?? this.padding, padding: padding ?? this.padding,
leadingPadding: leadingPadding ?? this.leadingPadding, leadingPadding: leadingPadding ?? this.leadingPadding,
); );
...@@ -74,6 +84,7 @@ class MaterialBannerThemeData with Diagnosticable { ...@@ -74,6 +84,7 @@ class MaterialBannerThemeData with Diagnosticable {
return MaterialBannerThemeData( return MaterialBannerThemeData(
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t), contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t),
padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t), padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t),
leadingPadding: EdgeInsetsGeometry.lerp(a?.leadingPadding, b?.leadingPadding, t), leadingPadding: EdgeInsetsGeometry.lerp(a?.leadingPadding, b?.leadingPadding, t),
); );
...@@ -84,6 +95,7 @@ class MaterialBannerThemeData with Diagnosticable { ...@@ -84,6 +95,7 @@ class MaterialBannerThemeData with Diagnosticable {
return hashValues( return hashValues(
backgroundColor, backgroundColor,
contentTextStyle, contentTextStyle,
elevation,
padding, padding,
leadingPadding, leadingPadding,
); );
...@@ -98,6 +110,7 @@ class MaterialBannerThemeData with Diagnosticable { ...@@ -98,6 +110,7 @@ class MaterialBannerThemeData with Diagnosticable {
return other is MaterialBannerThemeData return other is MaterialBannerThemeData
&& other.backgroundColor == backgroundColor && other.backgroundColor == backgroundColor
&& other.contentTextStyle == contentTextStyle && other.contentTextStyle == contentTextStyle
&& other.elevation == elevation
&& other.padding == padding && other.padding == padding
&& other.leadingPadding == leadingPadding; && other.leadingPadding == leadingPadding;
} }
...@@ -107,6 +120,7 @@ class MaterialBannerThemeData with Diagnosticable { ...@@ -107,6 +120,7 @@ class MaterialBannerThemeData with Diagnosticable {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('leadingPadding', leadingPadding, defaultValue: null)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('leadingPadding', leadingPadding, defaultValue: null));
} }
......
...@@ -13,6 +13,7 @@ import 'package:flutter/widgets.dart'; ...@@ -13,6 +13,7 @@ import 'package:flutter/widgets.dart';
import 'app_bar.dart'; import 'app_bar.dart';
import 'banner.dart'; import 'banner.dart';
import 'banner_theme.dart';
import 'bottom_sheet.dart'; import 'bottom_sheet.dart';
import 'colors.dart'; import 'colors.dart';
import 'curves.dart'; import 'curves.dart';
...@@ -802,14 +803,18 @@ class _BodyBoxConstraints extends BoxConstraints { ...@@ -802,14 +803,18 @@ class _BodyBoxConstraints extends BoxConstraints {
double maxHeight = double.infinity, double maxHeight = double.infinity,
required this.bottomWidgetsHeight, required this.bottomWidgetsHeight,
required this.appBarHeight, required this.appBarHeight,
required this.materialBannerHeight,
}) : assert(bottomWidgetsHeight != null), }) : assert(bottomWidgetsHeight != null),
assert(bottomWidgetsHeight >= 0), assert(bottomWidgetsHeight >= 0),
assert(appBarHeight != null), assert(appBarHeight != null),
assert(appBarHeight >= 0), assert(appBarHeight >= 0),
assert(materialBannerHeight != null),
assert(materialBannerHeight >= 0),
super(minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight); super(minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight);
final double bottomWidgetsHeight; final double bottomWidgetsHeight;
final double appBarHeight; final double appBarHeight;
final double materialBannerHeight;
// RenderObject.layout() will only short-circuit its call to its performLayout // RenderObject.layout() will only short-circuit its call to its performLayout
// method if the new layout constraints are not == to the current constraints. // method if the new layout constraints are not == to the current constraints.
...@@ -820,13 +825,14 @@ class _BodyBoxConstraints extends BoxConstraints { ...@@ -820,13 +825,14 @@ class _BodyBoxConstraints extends BoxConstraints {
if (super != other) if (super != other)
return false; return false;
return other is _BodyBoxConstraints return other is _BodyBoxConstraints
&& other.materialBannerHeight == materialBannerHeight
&& other.bottomWidgetsHeight == bottomWidgetsHeight && other.bottomWidgetsHeight == bottomWidgetsHeight
&& other.appBarHeight == appBarHeight; && other.appBarHeight == appBarHeight;
} }
@override @override
int get hashCode { int get hashCode {
return hashValues(super.hashCode, bottomWidgetsHeight, appBarHeight); return hashValues(super.hashCode, materialBannerHeight, bottomWidgetsHeight, appBarHeight);
} }
} }
...@@ -866,7 +872,8 @@ class _BodyBuilder extends StatelessWidget { ...@@ -866,7 +872,8 @@ class _BodyBuilder extends StatelessWidget {
: metrics.padding.bottom; : metrics.padding.bottom;
final double top = extendBodyBehindAppBar final double top = extendBodyBehindAppBar
? math.max(metrics.padding.top, bodyConstraints.appBarHeight) ? math.max(metrics.padding.top,
bodyConstraints.appBarHeight + bodyConstraints.materialBannerHeight)
: metrics.padding.top; : metrics.padding.top;
return MediaQuery( return MediaQuery(
...@@ -898,6 +905,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -898,6 +905,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
required this.snackBarWidth, required this.snackBarWidth,
required this.extendBody, required this.extendBody,
required this.extendBodyBehindAppBar, required this.extendBodyBehindAppBar,
required this.extendBodyBehindMaterialBanner,
}) : assert(minInsets != null), }) : assert(minInsets != null),
assert(textDirection != null), assert(textDirection != null),
assert(geometryNotifier != null), assert(geometryNotifier != null),
...@@ -921,6 +929,8 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -921,6 +929,8 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
final bool isSnackBarFloating; final bool isSnackBarFloating;
final double? snackBarWidth; final double? snackBarWidth;
final bool extendBodyBehindMaterialBanner;
@override @override
void performLayout(Size size) { void performLayout(Size size) {
final BoxConstraints looseConstraints = BoxConstraints.loose(size); final BoxConstraints looseConstraints = BoxConstraints.loose(size);
...@@ -960,6 +970,17 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -960,6 +970,17 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
positionChild(_ScaffoldSlot.persistentFooter, Offset(0.0, math.max(0.0, bottom - bottomWidgetsHeight))); positionChild(_ScaffoldSlot.persistentFooter, Offset(0.0, math.max(0.0, bottom - bottomWidgetsHeight)));
} }
Size materialBannerSize = Size.zero;
if (hasChild(_ScaffoldSlot.materialBanner)) {
materialBannerSize = layoutChild(_ScaffoldSlot.materialBanner, fullWidthConstraints);
positionChild(_ScaffoldSlot.materialBanner, Offset(0.0, appBarHeight));
// Push content down only if elevation is 0.
if (!extendBodyBehindMaterialBanner) {
contentTop += materialBannerSize.height;
}
}
// Set the content bottom to account for the greater of the height of any // Set the content bottom to account for the greater of the height of any
// bottom-anchored material widgets or of the keyboard or other // bottom-anchored material widgets or of the keyboard or other
// bottom-anchored system UI. // bottom-anchored system UI.
...@@ -977,6 +998,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -977,6 +998,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
final BoxConstraints bodyConstraints = _BodyBoxConstraints( final BoxConstraints bodyConstraints = _BodyBoxConstraints(
maxWidth: fullWidthConstraints.maxWidth, maxWidth: fullWidthConstraints.maxWidth,
maxHeight: bodyMaxHeight, maxHeight: bodyMaxHeight,
materialBannerHeight: materialBannerSize.height,
bottomWidgetsHeight: extendBody ? bottomWidgetsHeight : 0.0, bottomWidgetsHeight: extendBody ? bottomWidgetsHeight : 0.0,
appBarHeight: appBarHeight, appBarHeight: appBarHeight,
); );
...@@ -1013,11 +1035,6 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -1013,11 +1035,6 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
snackBarSize = layoutChild(_ScaffoldSlot.snackBar, fullWidthConstraints); snackBarSize = layoutChild(_ScaffoldSlot.snackBar, fullWidthConstraints);
} }
Size materialBannerSize = Size.zero;
if (hasChild(_ScaffoldSlot.materialBanner)) {
materialBannerSize = layoutChild(_ScaffoldSlot.materialBanner, fullWidthConstraints);
}
if (hasChild(_ScaffoldSlot.bottomSheet)) { if (hasChild(_ScaffoldSlot.bottomSheet)) {
final BoxConstraints bottomSheetConstraints = BoxConstraints( final BoxConstraints bottomSheetConstraints = BoxConstraints(
maxWidth: fullWidthConstraints.maxWidth, maxWidth: fullWidthConstraints.maxWidth,
...@@ -1086,17 +1103,6 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { ...@@ -1086,17 +1103,6 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
positionChild(_ScaffoldSlot.snackBar, Offset(xOffset, snackBarYOffsetBase - snackBarSize.height)); positionChild(_ScaffoldSlot.snackBar, Offset(xOffset, snackBarYOffsetBase - snackBarSize.height));
} }
if (hasChild(_ScaffoldSlot.materialBanner)) {
if (materialBannerSize == Size.zero) {
materialBannerSize = layoutChild(
_ScaffoldSlot.materialBanner,
fullWidthConstraints,
);
}
positionChild(_ScaffoldSlot.materialBanner, Offset(0.0, appBarHeight));
}
if (hasChild(_ScaffoldSlot.statusBar)) { if (hasChild(_ScaffoldSlot.statusBar)) {
layoutChild(_ScaffoldSlot.statusBar, fullWidthConstraints.tighten(height: minInsets.top)); layoutChild(_ScaffoldSlot.statusBar, fullWidthConstraints.tighten(height: minInsets.top));
positionChild(_ScaffoldSlot.statusBar, Offset.zero); positionChild(_ScaffoldSlot.statusBar, Offset.zero);
...@@ -2927,8 +2933,13 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto ...@@ -2927,8 +2933,13 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
); );
} }
bool extendBodyBehindMaterialBanner = false;
// MaterialBanner set by ScaffoldMessenger // MaterialBanner set by ScaffoldMessenger
if (_messengerMaterialBanner != null) { if (_messengerMaterialBanner != null) {
final MaterialBannerThemeData bannerTheme = MaterialBannerTheme.of(context);
final double elevation = _messengerMaterialBanner?._widget.elevation ?? bannerTheme.elevation ?? 0.0;
extendBodyBehindMaterialBanner = elevation != 0.0;
_addIfNonNull( _addIfNonNull(
children, children,
_messengerMaterialBanner?._widget, _messengerMaterialBanner?._widget,
...@@ -3070,6 +3081,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto ...@@ -3070,6 +3081,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
previousFloatingActionButtonLocation: _previousFloatingActionButtonLocation!, previousFloatingActionButtonLocation: _previousFloatingActionButtonLocation!,
textDirection: textDirection, textDirection: textDirection,
isSnackBarFloating: isSnackBarFloating, isSnackBarFloating: isSnackBarFloating,
extendBodyBehindMaterialBanner: extendBodyBehindMaterialBanner,
snackBarWidth: snackBarWidth, snackBarWidth: snackBarWidth,
), ),
children: children, children: children,
......
...@@ -24,8 +24,8 @@ void main() { ...@@ -24,8 +24,8 @@ void main() {
), ),
); );
final Container container = _getContainerFromBanner(tester); final Material material = _getMaterialFromBanner(tester);
expect(container.color, color); expect(material.color, color);
}); });
testWidgets('Custom background color respected when presented by ScaffoldMessenger', (WidgetTester tester) async { testWidgets('Custom background color respected when presented by ScaffoldMessenger', (WidgetTester tester) async {
...@@ -63,7 +63,7 @@ void main() { ...@@ -63,7 +63,7 @@ void main() {
await tester.tap(find.byKey(tapTarget)); await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(_getContainerFromText(tester, contentText).color, color); expect(_getMaterialFromText(tester, contentText).color, color);
}); });
testWidgets('Custom content TextStyle respected', (WidgetTester tester) async { testWidgets('Custom content TextStyle respected', (WidgetTester tester) async {
...@@ -259,6 +259,97 @@ void main() { ...@@ -259,6 +259,97 @@ void main() {
expect(contentBottomLeft.dx, lessThan(actionsTopRight.dx)); expect(contentBottomLeft.dx, lessThan(actionsTopRight.dx));
}); });
group('MaterialBanner elevation', () {
Widget buildBanner(Key tapTarget, {double? elevation, double? themeElevation}) {
return MaterialApp(
theme: ThemeData(bannerTheme: MaterialBannerThemeData(elevation: themeElevation)),
home: Scaffold(
body: Builder(
builder: (BuildContext context) {
return GestureDetector(
key: tapTarget,
onTap: () {
ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner(
content: const Text('MaterialBanner'),
elevation: elevation,
actions: <Widget>[
TextButton(
child: const Text('DISMISS'),
onPressed: () => ScaffoldMessenger.of(context).hideCurrentMaterialBanner(),
),
],
));
},
behavior: HitTestBehavior.opaque,
child: const SizedBox(
height: 100.0,
width: 100.0,
),
);
},
),
),
);
}
testWidgets('Elevation defaults to 0', (WidgetTester tester) async {
const Key tapTarget = Key('tap-target');
await tester.pumpWidget(buildBanner(tapTarget));
await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle();
expect(_getMaterialFromBanner(tester).elevation, 0.0);
await tester.tap(find.text('DISMISS'));
await tester.pumpAndSettle();
await tester.pumpWidget(buildBanner(tapTarget, themeElevation: 6.0));
await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle();
expect(_getMaterialFromBanner(tester).elevation, 6.0);
await tester.tap(find.text('DISMISS'));
await tester.pumpAndSettle();
await tester.pumpWidget(buildBanner(tapTarget, elevation: 3.0, themeElevation: 6.0));
await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle();
expect(_getMaterialFromBanner(tester).elevation, 3.0);
await tester.tap(find.text('DISMISS'));
await tester.pumpAndSettle();
});
testWidgets('Uses elevation of MaterialBannerTheme by default', (WidgetTester tester) async {
const Key tapTarget = Key('tap-target');
await tester.pumpWidget(buildBanner(tapTarget, themeElevation: 6.0));
await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle();
expect(_getMaterialFromBanner(tester).elevation, 6.0);
await tester.tap(find.text('DISMISS'));
await tester.pumpAndSettle();
await tester.pumpWidget(buildBanner(tapTarget, elevation: 3.0, themeElevation: 6.0));
await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle();
expect(_getMaterialFromBanner(tester).elevation, 3.0);
await tester.tap(find.text('DISMISS'));
await tester.pumpAndSettle();
});
testWidgets('Scaffold body is pushed down if elevation is 0', (WidgetTester tester) async {
const Key tapTarget = Key('tap-target');
await tester.pumpWidget(buildBanner(tapTarget, elevation: 0.0));
await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle();
final Offset contentTopLeft = tester.getTopLeft(find.byKey(tapTarget));
final Offset bannerBottomLeft = tester.getBottomLeft(find.byType(MaterialBanner));
expect(contentTopLeft.dx, 0.0);
expect(contentTopLeft.dy, greaterThanOrEqualTo(bannerBottomLeft.dy));
});
});
testWidgets('MaterialBanner control test', (WidgetTester tester) async { testWidgets('MaterialBanner control test', (WidgetTester tester) async {
const String helloMaterialBanner = 'Hello MaterialBanner'; const String helloMaterialBanner = 'Hello MaterialBanner';
const Key tapTarget = Key('tap-target'); const Key tapTarget = Key('tap-target');
...@@ -984,12 +1075,12 @@ void main() { ...@@ -984,12 +1075,12 @@ void main() {
}); });
} }
Container _getContainerFromBanner(WidgetTester tester) { Material _getMaterialFromBanner(WidgetTester tester) {
return tester.widget<Container>(find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Container)).first); return tester.widget<Material>(find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Material)).first);
} }
Container _getContainerFromText(WidgetTester tester, String text) { Material _getMaterialFromText(WidgetTester tester, String text) {
return tester.widget<Container>(find.widgetWithText(Container, text).first); return tester.widget<Material>(find.widgetWithText(Material, text).first);
} }
RenderParagraph _getTextRenderObjectFromDialog(WidgetTester tester, String text) { RenderParagraph _getTextRenderObjectFromDialog(WidgetTester tester, String text) {
......
...@@ -64,9 +64,9 @@ void main() { ...@@ -64,9 +64,9 @@ void main() {
), ),
)); ));
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
expect(container.color, const Color(0xffffffff)); expect(material.color, const Color(0xffffffff));
// Default value for ThemeData.typography is Typography.material2014() // Default value for ThemeData.typography is Typography.material2014()
expect(content.text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2)); expect(content.text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2));
}); });
...@@ -104,9 +104,9 @@ void main() { ...@@ -104,9 +104,9 @@ void main() {
await tester.tap(find.byKey(tapTarget)); await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
expect(container.color, const Color(0xffffffff)); expect(material.color, const Color(0xffffffff));
// Default value for ThemeData.typography is Typography.material2014() // Default value for ThemeData.typography is Typography.material2014()
expect(content.text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2)); expect(content.text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().black.bodyText2));
}); });
...@@ -130,18 +130,18 @@ void main() { ...@@ -130,18 +130,18 @@ void main() {
), ),
)); ));
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
expect(container.color, bannerTheme.backgroundColor); expect(material.color, bannerTheme.backgroundColor);
expect(content.text.style, bannerTheme.contentTextStyle); expect(content.text.style, bannerTheme.contentTextStyle);
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
final Offset containerTopLeft = tester.getTopLeft(_containerFinder()); final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit));
expect(contentTopLeft.dy - containerTopLeft.dy, 24); expect(contentTopLeft.dy - materialTopLeft.dy, 24);
expect(contentTopLeft.dx - containerTopLeft.dx, 41); expect(contentTopLeft.dx - materialTopLeft.dx, 41);
expect(leadingTopLeft.dy - containerTopLeft.dy, 19); expect(leadingTopLeft.dy - materialTopLeft.dy, 19);
expect(leadingTopLeft.dx - containerTopLeft.dx, 11); expect(leadingTopLeft.dx - materialTopLeft.dx, 11);
}); });
testWidgets('MaterialBanner uses values from MaterialBannerThemeData when presented by ScaffoldMessenger', (WidgetTester tester) async { testWidgets('MaterialBanner uses values from MaterialBannerThemeData when presented by ScaffoldMessenger', (WidgetTester tester) async {
...@@ -180,18 +180,18 @@ void main() { ...@@ -180,18 +180,18 @@ void main() {
await tester.tap(find.byKey(tapTarget)); await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
expect(container.color, bannerTheme.backgroundColor); expect(material.color, bannerTheme.backgroundColor);
expect(content.text.style, bannerTheme.contentTextStyle); expect(content.text.style, bannerTheme.contentTextStyle);
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
final Offset containerTopLeft = tester.getTopLeft(_containerFinder()); final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit));
expect(contentTopLeft.dy - containerTopLeft.dy, 24); expect(contentTopLeft.dy - materialTopLeft.dy, 24);
expect(contentTopLeft.dx - containerTopLeft.dx, 41); expect(contentTopLeft.dx - materialTopLeft.dx, 41);
expect(leadingTopLeft.dy - containerTopLeft.dy, 19); expect(leadingTopLeft.dy - materialTopLeft.dy, 19);
expect(leadingTopLeft.dx - containerTopLeft.dx, 11); expect(leadingTopLeft.dx - materialTopLeft.dx, 11);
}); });
testWidgets('MaterialBanner widget properties take priority over theme', (WidgetTester tester) async { testWidgets('MaterialBanner widget properties take priority over theme', (WidgetTester tester) async {
...@@ -219,18 +219,18 @@ void main() { ...@@ -219,18 +219,18 @@ void main() {
), ),
)); ));
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
expect(container.color, backgroundColor); expect(material.color, backgroundColor);
expect(content.text.style, textStyle); expect(content.text.style, textStyle);
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
final Offset containerTopLeft = tester.getTopLeft(_containerFinder()); final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit));
expect(contentTopLeft.dy - containerTopLeft.dy, 29); expect(contentTopLeft.dy - materialTopLeft.dy, 29);
expect(contentTopLeft.dx - containerTopLeft.dx, 58); expect(contentTopLeft.dx - materialTopLeft.dx, 58);
expect(leadingTopLeft.dy - containerTopLeft.dy, 24); expect(leadingTopLeft.dy - materialTopLeft.dy, 24);
expect(leadingTopLeft.dx - containerTopLeft.dx, 22); expect(leadingTopLeft.dx - materialTopLeft.dx, 22);
}); });
testWidgets('MaterialBanner widget properties take priority over theme when presented by ScaffoldMessenger', (WidgetTester tester) async { testWidgets('MaterialBanner widget properties take priority over theme when presented by ScaffoldMessenger', (WidgetTester tester) async {
...@@ -275,18 +275,18 @@ void main() { ...@@ -275,18 +275,18 @@ void main() {
await tester.tap(find.byKey(tapTarget)); await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText); final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
expect(container.color, backgroundColor); expect(material.color, backgroundColor);
expect(content.text.style, textStyle); expect(content.text.style, textStyle);
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText)); final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
final Offset containerTopLeft = tester.getTopLeft(_containerFinder()); final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit)); final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.ac_unit));
expect(contentTopLeft.dy - containerTopLeft.dy, 29); expect(contentTopLeft.dy - materialTopLeft.dy, 29);
expect(contentTopLeft.dx - containerTopLeft.dx, 58); expect(contentTopLeft.dx - materialTopLeft.dx, 58);
expect(leadingTopLeft.dy - containerTopLeft.dy, 24); expect(leadingTopLeft.dy - materialTopLeft.dy, 24);
expect(leadingTopLeft.dx - containerTopLeft.dx, 22); expect(leadingTopLeft.dx - materialTopLeft.dx, 22);
}); });
testWidgets('MaterialBanner uses color scheme when necessary', (WidgetTester tester) async { testWidgets('MaterialBanner uses color scheme when necessary', (WidgetTester tester) async {
...@@ -307,8 +307,8 @@ void main() { ...@@ -307,8 +307,8 @@ void main() {
), ),
)); ));
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
expect(container.color, colorScheme.surface); expect(material.color, colorScheme.surface);
}); });
testWidgets('MaterialBanner uses color scheme when necessary when presented by ScaffoldMessenger', (WidgetTester tester) async { testWidgets('MaterialBanner uses color scheme when necessary when presented by ScaffoldMessenger', (WidgetTester tester) async {
...@@ -346,8 +346,8 @@ void main() { ...@@ -346,8 +346,8 @@ void main() {
await tester.tap(find.byKey(tapTarget)); await tester.tap(find.byKey(tapTarget));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
final Container container = _getContainerFromText(tester, contentText); final Material material = _getMaterialFromText(tester, contentText);
expect(container.color, colorScheme.surface); expect(material.color, colorScheme.surface);
}); });
} }
...@@ -360,12 +360,12 @@ MaterialBannerThemeData _bannerTheme() { ...@@ -360,12 +360,12 @@ MaterialBannerThemeData _bannerTheme() {
); );
} }
Container _getContainerFromText(WidgetTester tester, String text) { Material _getMaterialFromText(WidgetTester tester, String text) {
return tester.widget<Container>(find.widgetWithText(Container, text).first); return tester.widget<Material>(find.widgetWithText(Material, text).first);
} }
Finder _containerFinder() { Finder _materialFinder() {
return find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Container)).first; return find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Material)).first;
} }
RenderParagraph _getTextRenderObjectFromDialog(WidgetTester tester, String text) { RenderParagraph _getTextRenderObjectFromDialog(WidgetTester tester, String text) {
......
...@@ -211,8 +211,8 @@ void main() { ...@@ -211,8 +211,8 @@ void main() {
} }
Color bannerColor() { Color bannerColor() {
return tester.widget<Container>( return tester.widget<Material>(
find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Container)).first, find.descendant(of: find.byType(MaterialBanner), matching: find.byType(Material)).first,
).color!; ).color!;
} }
......
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