diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart index 0df507620b..c68208c397 100644 --- a/packages/flutter/lib/src/material/material.dart +++ b/packages/flutter/lib/src/material/material.dart @@ -97,8 +97,8 @@ abstract class MaterialInkController { /// splashes and ink highlights) won't move to account for the new layout. /// /// In general, the features of a [Material] should not change over time (e.g. a -/// [Material] should not change its [color] or [type]). The one exception is -/// the [elevation], changes to which will be animated. +/// [Material] should not change its [color], [shadowColor] or [type]). The one +/// exception is the [elevation], changes to which will be animated. /// /// See also: /// @@ -108,17 +108,19 @@ abstract class MaterialInkController { class Material extends StatefulWidget { /// Creates a piece of material. /// - /// The [type] and the [elevation] arguments must not be null. + /// The [type], [elevation] and [shadowColor] arguments must not be null. const Material({ Key key, this.type: MaterialType.canvas, this.elevation: 0.0, this.color, + this.shadowColor: const Color(0xFF000000), this.textStyle, this.borderRadius, this.child, }) : assert(type != null), assert(elevation != null), + assert(shadowColor != null), assert(!(identical(type, MaterialType.circle) && borderRadius != null)), super(key: key); @@ -148,6 +150,11 @@ class Material extends StatefulWidget { /// By default, the color is derived from the [type] of material. final Color color; + /// The color to paint the shadow below the material. + /// + /// Defaults to fully opaque black. + final Color shadowColor; + /// The typographical style to use for text within this material. final TextStyle textStyle; @@ -178,8 +185,9 @@ class Material extends StatefulWidget { void debugFillProperties(DiagnosticPropertiesBuilder description) { super.debugFillProperties(description); description.add(new EnumProperty('type', type)); - description.add(new DoubleProperty('elevation', elevation)); + description.add(new DoubleProperty('elevation', elevation, defaultValue: 0.0)); description.add(new DiagnosticsProperty('color', color, defaultValue: null)); + description.add(new DiagnosticsProperty('shadowColor', shadowColor, defaultValue: const Color(0xFF000000))); textStyle?.debugFillProperties(description, prefix: 'textStyle.'); description.add(new EnumProperty('borderRadius', borderRadius, defaultValue: null)); } @@ -238,6 +246,7 @@ class _MaterialState extends State with TickerProviderStateMixin { shape: BoxShape.circle, elevation: widget.elevation, color: backgroundColor, + shadowColor: widget.shadowColor, animateColor: false, child: contents, ); @@ -258,6 +267,7 @@ class _MaterialState extends State with TickerProviderStateMixin { borderRadius: radius ?? BorderRadius.zero, elevation: widget.elevation, color: backgroundColor, + shadowColor: widget.shadowColor, animateColor: false, child: contents, ); diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 90f56fa2e7..af6d65eb83 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -1298,20 +1298,23 @@ class RenderPhysicalModel extends _RenderCustomClip { /// /// The [color] is required. /// - /// The [shape], [elevation], and [color] must not be null. + /// The [shape], [elevation], [color], and [shadowColor] must not be null. RenderPhysicalModel({ RenderBox child, BoxShape shape: BoxShape.rectangle, BorderRadius borderRadius, double elevation: 0.0, @required Color color, + Color shadowColor: const Color(0xFF000000), }) : assert(shape != null), assert(elevation != null), assert(color != null), + assert(shadowColor != null), _shape = shape, _borderRadius = borderRadius, _elevation = elevation, _color = color, + _shadowColor = shadowColor, super(child: child); /// The shape of the layer. @@ -1357,6 +1360,17 @@ class RenderPhysicalModel extends _RenderCustomClip { markNeedsPaint(); } + /// The shadow color. + Color get shadowColor => _shadowColor; + Color _shadowColor; + set shadowColor(Color value) { + assert(value != null); + if (shadowColor == value) + return; + _shadowColor = value; + markNeedsPaint(); + } + /// The background color. Color get color => _color; Color _color; @@ -1427,7 +1441,7 @@ class RenderPhysicalModel extends _RenderCustomClip { ); canvas.drawShadow( new Path()..addRRect(offsetClipRRect), - const Color(0xFF000000), + shadowColor, elevation, color.alpha != 0xFF, ); diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 0073c86d78..fab5d79305 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -648,17 +648,19 @@ class PhysicalModel extends SingleChildRenderObjectWidget { /// /// The [color] is required; physical things have a color. /// - /// The [shape], [elevation], and [color] must not be null. + /// The [shape], [elevation], [color], and [shadowColor] must not be null. const PhysicalModel({ Key key, this.shape: BoxShape.rectangle, this.borderRadius, this.elevation: 0.0, @required this.color, + this.shadowColor: const Color(0xFF000000), Widget child, }) : assert(shape != null), assert(elevation != null), assert(color != null), + assert(shadowColor != null), super(key: key, child: child); /// The type of shape. @@ -678,8 +680,11 @@ class PhysicalModel extends SingleChildRenderObjectWidget { /// The background color. final Color color; + /// The shadow color. + final Color shadowColor; + @override - RenderPhysicalModel createRenderObject(BuildContext context) => new RenderPhysicalModel(shape: shape, borderRadius: borderRadius, elevation: elevation, color: color); + RenderPhysicalModel createRenderObject(BuildContext context) => new RenderPhysicalModel(shape: shape, borderRadius: borderRadius, elevation: elevation, color: color, shadowColor: shadowColor); @override void updateRenderObject(BuildContext context, RenderPhysicalModel renderObject) { @@ -687,7 +692,8 @@ class PhysicalModel extends SingleChildRenderObjectWidget { ..shape = shape ..borderRadius = borderRadius ..elevation = elevation - ..color = color; + ..color = color + ..shadowColor = shadowColor; } @override @@ -697,6 +703,7 @@ class PhysicalModel extends SingleChildRenderObjectWidget { description.add(new DiagnosticsProperty('borderRadius', borderRadius)); description.add(new DoubleProperty('elevation', elevation)); description.add(new DiagnosticsProperty('color', color)); + description.add(new DiagnosticsProperty('shadowColor', shadowColor)); } } diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index a40a48c0d9..af0fcce8fc 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -931,10 +931,12 @@ class _AnimatedDefaultTextStyleState extends AnimatedWidgetBaseState new _AnimatedPhysicalModelState(); @@ -983,6 +996,8 @@ class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget { description.add(new DoubleProperty('elevation', elevation)); description.add(new DiagnosticsProperty('color', color)); description.add(new DiagnosticsProperty('animateColor', animateColor)); + description.add(new DiagnosticsProperty('shadowColor', shadowColor)); + description.add(new DiagnosticsProperty('animateShadowColor', animateShadowColor)); } } @@ -990,12 +1005,14 @@ class _AnimatedPhysicalModelState extends AnimatedWidgetBaseState _elevation; ColorTween _color; + ColorTween _shadowColor; @override void forEachTween(TweenVisitor visitor) { _borderRadius = visitor(_borderRadius, widget.borderRadius, (dynamic value) => new BorderRadiusTween(begin: value)); _elevation = visitor(_elevation, widget.elevation, (dynamic value) => new Tween(begin: value)); _color = visitor(_color, widget.color, (dynamic value) => new ColorTween(begin: value)); + _shadowColor = visitor(_shadowColor, widget.shadowColor, (dynamic value) => new ColorTween(begin: value)); } @override @@ -1006,6 +1023,9 @@ class _AnimatedPhysicalModelState extends AnimatedWidgetBaseState