Commit d9153a13 authored by Hans Muller's avatar Hans Muller

Update shadow rendering

Shadows now render as three seprate MaskFilter.blur components per the most recent Material spec.

The shadows Map was replaced by a similar Map called elevationToShadow with entries that match the 10 elevations specifed by http://www.google.com/design/spec/what-is-material/elevation-shadows.html.

The "level" property (many classes) is now called "elevation", to match the Material spec.

BoxShadow now includes a spreadRadius parameter - as in CSS box-shadow. Renamed the BoxShadow blur property to blurRadius to further align BoxShadow with CSS box-shadow.
parent b20a1f4a
...@@ -13,7 +13,7 @@ void main() { ...@@ -13,7 +13,7 @@ void main() {
gradient: new RadialGradient( gradient: new RadialGradient(
center: Point.origin, radius: 500.0, center: Point.origin, radius: 500.0,
colors: <Color>[Colors.yellow[500], Colors.blue[500]]), colors: <Color>[Colors.yellow[500], Colors.blue[500]]),
boxShadow: shadows[3]) boxShadow: elevationToShadow[8])
); );
var paddedBox = new RenderPadding( var paddedBox = new RenderPadding(
padding: const EdgeDims.all(50.0), padding: const EdgeDims.all(50.0),
......
...@@ -146,7 +146,7 @@ class StockHomeState extends State<StockHome> { ...@@ -146,7 +146,7 @@ class StockHomeState extends State<StockHome> {
Widget buildToolBar() { Widget buildToolBar() {
return new ToolBar( return new ToolBar(
level: 0, elevation: 0,
left: new IconButton( left: new IconButton(
icon: "navigation/menu", icon: "navigation/menu",
onPressed: _showDrawer onPressed: _showDrawer
......
...@@ -100,7 +100,7 @@ Widget statusBox(Widget child) { ...@@ -100,7 +100,7 @@ Widget statusBox(Widget child) {
decoration: const BoxDecoration( decoration: const BoxDecoration(
boxShadow: const <BoxShadow>[ boxShadow: const <BoxShadow>[
const BoxShadow( const BoxShadow(
color: mediumGray, offset: const Offset(6.0, 6.0), blur: 5.0) color: mediumGray, offset: const Offset(6.0, 6.0), blurRadius: 5.0)
], ],
backgroundColor: darkGray backgroundColor: darkGray
), ),
......
...@@ -23,7 +23,7 @@ class Card extends StatelessComponent { ...@@ -23,7 +23,7 @@ class Card extends StatelessComponent {
child: new Material( child: new Material(
color: color, color: color,
type: MaterialType.card, type: MaterialType.card,
level: 2, elevation: 8,
child: child child: child
) )
); );
......
...@@ -102,7 +102,7 @@ class Dialog extends StatelessComponent { ...@@ -102,7 +102,7 @@ class Dialog extends StatelessComponent {
child: new ConstrainedBox( child: new ConstrainedBox(
constraints: new BoxConstraints(minWidth: 280.0), constraints: new BoxConstraints(minWidth: 280.0),
child: new Material( child: new Material(
level: 4, elevation: 24,
color: _getColor(context), color: _getColor(context),
type: MaterialType.card, type: MaterialType.card,
child: new IntrinsicWidth( child: new IntrinsicWidth(
......
...@@ -36,7 +36,7 @@ class _Drawer extends StatelessComponent { ...@@ -36,7 +36,7 @@ class _Drawer extends StatelessComponent {
child: new ConstrainedBox( child: new ConstrainedBox(
constraints: const BoxConstraints.expand(width: _kWidth), constraints: const BoxConstraints.expand(width: _kWidth),
child: new Material( child: new Material(
level: route.level, elevation: route.elevation,
child: route.child child: route.child
) )
) )
...@@ -51,10 +51,10 @@ enum _DrawerState { ...@@ -51,10 +51,10 @@ enum _DrawerState {
} }
class _DrawerRoute extends OverlayRoute { class _DrawerRoute extends OverlayRoute {
_DrawerRoute({ this.child, this.level }); _DrawerRoute({ this.child, this.elevation });
final Widget child; final Widget child;
final int level; final int elevation;
List<WidgetBuilder> get builders => <WidgetBuilder>[ _build ]; List<WidgetBuilder> get builders => <WidgetBuilder>[ _build ];
...@@ -212,6 +212,6 @@ class _DrawerControllerState extends State<_DrawerController> { ...@@ -212,6 +212,6 @@ class _DrawerControllerState extends State<_DrawerController> {
} }
} }
void showDrawer({ BuildContext context, Widget child, int level: 3 }) { void showDrawer({ BuildContext context, Widget child, int elevation: 16 }) {
Navigator.of(context).push(new _DrawerRoute(child: child, level: level)); Navigator.of(context).push(new _DrawerRoute(child: child, elevation: elevation));
} }
...@@ -85,7 +85,7 @@ class _DropdownMenu extends StatusTransitionComponent { ...@@ -85,7 +85,7 @@ class _DropdownMenu extends StatusTransitionComponent {
final BoxPainter menuPainter = new BoxPainter(new BoxDecoration( final BoxPainter menuPainter = new BoxPainter(new BoxDecoration(
backgroundColor: Theme.of(context).canvasColor, backgroundColor: Theme.of(context).canvasColor,
borderRadius: 2.0, borderRadius: 2.0,
boxShadow: shadows[route.level] boxShadow: elevationToShadow[route.elevation]
)); ));
final RenderBox renderBox = Navigator.of(context).context.findRenderObject(); final RenderBox renderBox = Navigator.of(context).context.findRenderObject();
...@@ -129,13 +129,13 @@ class _MenuRoute extends TransitionRoute { ...@@ -129,13 +129,13 @@ class _MenuRoute extends TransitionRoute {
this.items, this.items,
this.selectedIndex, this.selectedIndex,
this.rect, this.rect,
this.level: 4 this.elevation: 8
}); });
final Completer completer; final Completer completer;
final Rect rect; final Rect rect;
final List<DropdownMenuItem> items; final List<DropdownMenuItem> items;
final int level; final int elevation;
final int selectedIndex; final int selectedIndex;
bool get opaque => false; bool get opaque => false;
...@@ -183,13 +183,13 @@ class DropdownButton<T> extends StatelessComponent { ...@@ -183,13 +183,13 @@ class DropdownButton<T> extends StatelessComponent {
this.items, this.items,
this.value, this.value,
this.onChanged, this.onChanged,
this.level: 4 this.elevation: 8
}) : super(key: key); }) : super(key: key);
final List<DropdownMenuItem<T>> items; final List<DropdownMenuItem<T>> items;
final T value; final T value;
final ValueChanged<T> onChanged; final ValueChanged<T> onChanged;
final int level; final int elevation;
void _showDropdown(BuildContext context, int selectedIndex, GlobalKey indexedStackKey) { void _showDropdown(BuildContext context, int selectedIndex, GlobalKey indexedStackKey) {
final RenderBox renderBox = indexedStackKey.currentContext.findRenderObject(); final RenderBox renderBox = indexedStackKey.currentContext.findRenderObject();
...@@ -200,7 +200,7 @@ class DropdownButton<T> extends StatelessComponent { ...@@ -200,7 +200,7 @@ class DropdownButton<T> extends StatelessComponent {
items: items, items: items,
selectedIndex: selectedIndex, selectedIndex: selectedIndex,
rect: _kMenuHorizontalPadding.inflateRect(rect), rect: _kMenuHorizontalPadding.inflateRect(rect),
level: level elevation: elevation
)); ));
completer.future.then((T newValue) { completer.future.then((T newValue) {
if (onChanged != null) if (onChanged != null)
......
...@@ -22,7 +22,7 @@ class FlatButton extends MaterialButton { ...@@ -22,7 +22,7 @@ class FlatButton extends MaterialButton {
class _FlatButtonState extends MaterialButtonState<FlatButton> { class _FlatButtonState extends MaterialButtonState<FlatButton> {
int get level => 0; int get elevation => 0;
Color getColor(BuildContext context, { bool highlight }) { Color getColor(BuildContext context, { bool highlight }) {
if (!config.enabled || !highlight) if (!config.enabled || !highlight)
......
...@@ -50,7 +50,7 @@ class _FloatingActionButtonState extends State<FloatingActionButton> { ...@@ -50,7 +50,7 @@ class _FloatingActionButtonState extends State<FloatingActionButton> {
return new Material( return new Material(
color: materialColor, color: materialColor,
type: MaterialType.circle, type: MaterialType.circle,
level: _highlight ? 3 : 2, elevation: _highlight ? 12 : 6,
child: new ClipOval( child: new ClipOval(
child: new Container( child: new Container(
width: _kSize, width: _kSize,
......
...@@ -23,16 +23,16 @@ class Material extends StatelessComponent { ...@@ -23,16 +23,16 @@ class Material extends StatelessComponent {
Key key, Key key,
this.child, this.child,
this.type: MaterialType.canvas, this.type: MaterialType.canvas,
this.level: 0, this.elevation: 0,
this.color, this.color,
this.textStyle this.textStyle
}) : super(key: key) { }) : super(key: key) {
assert(level != null); assert(elevation != null);
} }
final Widget child; final Widget child;
final MaterialType type; final MaterialType type;
final int level; final int elevation;
final Color color; final Color color;
final TextStyle textStyle; final TextStyle textStyle;
...@@ -72,7 +72,7 @@ class Material extends StatelessComponent { ...@@ -72,7 +72,7 @@ class Material extends StatelessComponent {
decoration: new BoxDecoration( decoration: new BoxDecoration(
backgroundColor: _getBackgroundColor(context), backgroundColor: _getBackgroundColor(context),
borderRadius: _kEdges[type], borderRadius: _kEdges[type],
boxShadow: level == 0 ? null : shadows[level], boxShadow: elevation == 0 ? null : elevationToShadow[elevation],
shape: type == MaterialType.circle ? Shape.circle : Shape.rectangle shape: type == MaterialType.circle ? Shape.circle : Shape.rectangle
), ),
child: contents child: contents
......
...@@ -56,7 +56,7 @@ abstract class MaterialButton extends StatefulComponent { ...@@ -56,7 +56,7 @@ abstract class MaterialButton extends StatefulComponent {
abstract class MaterialButtonState<T extends MaterialButton> extends State<T> { abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
bool highlight = false; bool highlight = false;
int get level; int get elevation;
Color getColor(BuildContext context, { bool highlight }); Color getColor(BuildContext context, { bool highlight });
ThemeBrightness getColorBrightness(BuildContext context); ThemeBrightness getColorBrightness(BuildContext context);
...@@ -102,7 +102,7 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> { ...@@ -102,7 +102,7 @@ abstract class MaterialButtonState<T extends MaterialButton> extends State<T> {
margin: new EdgeDims.all(8.0), margin: new EdgeDims.all(8.0),
child: new Material( child: new Material(
type: MaterialType.button, type: MaterialType.button,
level: level, elevation: elevation,
textStyle: Theme.of(context).text.button.copyWith(color: getTextColor(context)), textStyle: Theme.of(context).text.button.copyWith(color: getTextColor(context)),
child: new InkWell( child: new InkWell(
onTap: config.enabled ? config.onPressed : null, onTap: config.enabled ? config.onPressed : null,
......
...@@ -34,7 +34,7 @@ class _PopupMenu extends StatelessComponent { ...@@ -34,7 +34,7 @@ class _PopupMenu extends StatelessComponent {
final BoxPainter painter = new BoxPainter(new BoxDecoration( final BoxPainter painter = new BoxPainter(new BoxDecoration(
backgroundColor: Theme.of(context).canvasColor, backgroundColor: Theme.of(context).canvasColor,
borderRadius: 2.0, borderRadius: 2.0,
boxShadow: shadows[route.level] boxShadow: elevationToShadow[route.elevation]
)); ));
double unit = 1.0 / (route.items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade. double unit = 1.0 / (route.items.length + 1.5); // 1.0 for the width and 0.5 for the last item's fade.
...@@ -93,11 +93,11 @@ class _PopupMenu extends StatelessComponent { ...@@ -93,11 +93,11 @@ class _PopupMenu extends StatelessComponent {
} }
class _MenuRoute extends ModalRoute { class _MenuRoute extends ModalRoute {
_MenuRoute({ Completer completer, this.position, this.items, this.level }) : super(completer: completer); _MenuRoute({ Completer completer, this.position, this.items, this.elevation }) : super(completer: completer);
final ModalPosition position; final ModalPosition position;
final List<PopupMenuItem> items; final List<PopupMenuItem> items;
final int level; final int elevation;
Performance createPerformance() { Performance createPerformance() {
Performance result = super.createPerformance(); Performance result = super.createPerformance();
...@@ -113,13 +113,13 @@ class _MenuRoute extends ModalRoute { ...@@ -113,13 +113,13 @@ class _MenuRoute extends ModalRoute {
Widget buildPage(BuildContext context) => new _PopupMenu(route: this); Widget buildPage(BuildContext context) => new _PopupMenu(route: this);
} }
Future showMenu({ BuildContext context, ModalPosition position, List<PopupMenuItem> items, int level: 4 }) { Future showMenu({ BuildContext context, ModalPosition position, List<PopupMenuItem> items, int elevation: 8 }) {
Completer completer = new Completer(); Completer completer = new Completer();
Navigator.of(context).pushEphemeral(new _MenuRoute( Navigator.of(context).pushEphemeral(new _MenuRoute(
completer: completer, completer: completer,
position: position, position: position,
items: items, items: items,
level: level elevation: elevation
)); ));
return completer.future; return completer.future;
} }
...@@ -22,7 +22,7 @@ class RaisedButton extends MaterialButton { ...@@ -22,7 +22,7 @@ class RaisedButton extends MaterialButton {
class _RaisedButtonState extends MaterialButtonState<RaisedButton> { class _RaisedButtonState extends MaterialButtonState<RaisedButton> {
int get level => config.enabled ? (highlight ? 2 : 1) : 0; int get elevation => config.enabled ? (highlight ? 8 : 2) : 0;
Color getColor(BuildContext context, { bool highlight }) { Color getColor(BuildContext context, { bool highlight }) {
if (config.enabled) { if (config.enabled) {
......
...@@ -6,55 +6,72 @@ import 'dart:ui' show Color, Offset; ...@@ -6,55 +6,72 @@ import 'dart:ui' show Color, Offset;
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
const Map<int, List<BoxShadow>> shadows = const <int, List<BoxShadow>>{ // Based on http://www.google.com/design/spec/what-is-material/elevation-shadows.html
// Currently, only the elevation values that are bound to one or more components are
// defined here.
const Color _kKeyUmbraOpacity = const Color(0x33000000); // alpha = 0.2
const Color _kKeyPenumbraOpacity = const Color(0x24000000); // alpha = 0.14
const Color _kAmbientShadowOpacity = const Color(0x1F000000); // alpha = 0.12
const Map<int, List<BoxShadow>> elevationToShadow = const <int, List<BoxShadow>>{
1: const <BoxShadow>[ 1: const <BoxShadow>[
const BoxShadow( const BoxShadow(offset: const Offset(0.0, 2.0), blurRadius: 1.0, spreadRadius: -1.0, color: _kKeyUmbraOpacity),
color: const Color(0x1F000000), const BoxShadow(offset: const Offset(0.0, 1.0), blurRadius: 1.0, spreadRadius: 0.0, color: _kKeyPenumbraOpacity),
offset: const Offset(0.0, 1.0), const BoxShadow(offset: const Offset(0.0, 1.0), blurRadius: 3.0, spreadRadius: 0.0, color: _kAmbientShadowOpacity),
blur: 3.0), ],
const BoxShadow(
color: const Color(0x3D000000),
offset: const Offset(0.0, 1.0),
blur: 2.0),
],
2: const <BoxShadow>[ 2: const <BoxShadow>[
const BoxShadow( const BoxShadow(offset: const Offset(0.0, 3.0), blurRadius: 1.0, spreadRadius: -2.0, color: _kKeyUmbraOpacity),
color: const Color(0x29000000), const BoxShadow(offset: const Offset(0.0, 2.0), blurRadius: 2.0, spreadRadius: 0.0, color: _kKeyPenumbraOpacity),
offset: const Offset(0.0, 3.0), const BoxShadow(offset: const Offset(0.0, 1.0), blurRadius: 5.0, spreadRadius: 0.0, color: _kAmbientShadowOpacity),
blur: 6.0),
const BoxShadow(
color: const Color(0x3B000000),
offset: const Offset(0.0, 3.0),
blur: 6.0),
], ],
3: const <BoxShadow>[ 3: const <BoxShadow>[
const BoxShadow( const BoxShadow(offset: const Offset(0.0, 3.0), blurRadius: 3.0, spreadRadius: -2.0, color: _kKeyUmbraOpacity),
color: const Color(0x30000000), const BoxShadow(offset: const Offset(0.0, 3.0), blurRadius: 4.0, spreadRadius: 0.0, color: _kKeyPenumbraOpacity),
offset: const Offset(0.0, 10.0), const BoxShadow(offset: const Offset(0.0, 1.0), blurRadius: 8.0, spreadRadius: 0.0, color: _kAmbientShadowOpacity),
blur: 20.0),
const BoxShadow(
color: const Color(0x3B000000),
offset: const Offset(0.0, 6.0),
blur: 6.0),
], ],
4: const <BoxShadow>[ 4: const <BoxShadow>[
const BoxShadow( const BoxShadow(offset: const Offset(0.0, 2.0), blurRadius: 4.0, spreadRadius: -1.0, color: _kKeyUmbraOpacity),
color: const Color(0x40000000), const BoxShadow(offset: const Offset(0.0, 4.0), blurRadius: 5.0, spreadRadius: 0.0, color: _kKeyPenumbraOpacity),
offset: const Offset(0.0, 14.0), const BoxShadow(offset: const Offset(0.0, 1.0), blurRadius: 10.0, spreadRadius: 0.0, color: _kAmbientShadowOpacity),
blur: 28.0), ],
const BoxShadow(
color: const Color(0x38000000), 6: const <BoxShadow>[
offset: const Offset(0.0, 10.0), const BoxShadow(offset: const Offset(0.0, 3.0), blurRadius: 5.0, spreadRadius: -1.0, color: _kKeyUmbraOpacity),
blur: 10.0), const BoxShadow(offset: const Offset(0.0, 6.0), blurRadius: 10.0, spreadRadius: 0.0, color: _kKeyPenumbraOpacity),
], const BoxShadow(offset: const Offset(0.0, 1.0), blurRadius: 18.0, spreadRadius: 0.0, color: _kAmbientShadowOpacity),
5: const <BoxShadow>[ ],
const BoxShadow(
color: const Color(0x4E000000), 8: const <BoxShadow>[
offset: const Offset(0.0, 19.0), const BoxShadow(offset: const Offset(0.0, 5.0), blurRadius: 5.0, spreadRadius: -3.0, color: _kKeyUmbraOpacity),
blur: 28.0), const BoxShadow(offset: const Offset(0.0, 8.0), blurRadius: 10.0, spreadRadius: 1.0, color: _kKeyPenumbraOpacity),
const BoxShadow( const BoxShadow(offset: const Offset(0.0, 3.0), blurRadius: 14.0, spreadRadius: 2.0, color: _kAmbientShadowOpacity),
color: const Color(0x38000000), ],
offset: const Offset(0.0, 15.0),
blur: 12.0), 9: const <BoxShadow>[
const BoxShadow(offset: const Offset(0.0, 5.0), blurRadius: 6.0, spreadRadius: -3.0, color: _kKeyUmbraOpacity),
const BoxShadow(offset: const Offset(0.0, 9.0), blurRadius: 12.0, spreadRadius: 1.0, color: _kKeyPenumbraOpacity),
const BoxShadow(offset: const Offset(0.0, 3.0), blurRadius: 16.0, spreadRadius: 2.0, color: _kAmbientShadowOpacity),
],
12: const <BoxShadow>[
const BoxShadow(offset: const Offset(0.0, 7.0), blurRadius: 8.0, spreadRadius: -4.0, color: _kKeyUmbraOpacity),
const BoxShadow(offset: const Offset(0.0, 12.0), blurRadius: 17.0, spreadRadius: 2.0, color: _kKeyPenumbraOpacity),
const BoxShadow(offset: const Offset(0.0, 5.0), blurRadius: 22.0, spreadRadius: 4.0, color: _kAmbientShadowOpacity),
],
16: const <BoxShadow>[
const BoxShadow(offset: const Offset(0.0, 8.0), blurRadius: 10.0, spreadRadius: -5.0, color: _kKeyUmbraOpacity),
const BoxShadow(offset: const Offset(0.0, 16.0), blurRadius: 24.0, spreadRadius: 2.0, color: _kKeyPenumbraOpacity),
const BoxShadow(offset: const Offset(0.0, 6.0), blurRadius: 30.0, spreadRadius: 5.0, color: _kAmbientShadowOpacity),
],
24: const <BoxShadow>[
const BoxShadow(offset: const Offset(0.0, 11.0), blurRadius: 15.0, spreadRadius: -7.0, color: _kKeyUmbraOpacity),
const BoxShadow(offset: const Offset(0.0, 24.0), blurRadius: 38.0, spreadRadius: 3.0, color: _kKeyPenumbraOpacity),
const BoxShadow(offset: const Offset(0.0, 9.0), blurRadius: 46.0, spreadRadius: 8.0, color: _kAmbientShadowOpacity),
], ],
}; };
...@@ -77,7 +77,7 @@ class _SnackBar extends StatelessComponent { ...@@ -77,7 +77,7 @@ class _SnackBar extends StatelessComponent {
minHeight: kSnackBarHeight, minHeight: kSnackBarHeight,
maxHeight: kSnackBarHeight, maxHeight: kSnackBarHeight,
child: new Material( child: new Material(
level: 2, elevation: 6,
color: _kSnackBackground, color: _kSnackBackground,
child: new Container( child: new Container(
margin: const EdgeDims.symmetric(horizontal: _kSideMargins), margin: const EdgeDims.symmetric(horizontal: _kSideMargins),
......
...@@ -134,8 +134,8 @@ class _RenderSwitch extends RenderToggleable { ...@@ -134,8 +134,8 @@ class _RenderSwitch extends RenderToggleable {
// Draw the raised thumb with a shadow // Draw the raised thumb with a shadow
paint.color = thumbColor; paint.color = thumbColor;
ShadowDrawLooperBuilder builder = new ShadowDrawLooperBuilder(); ShadowDrawLooperBuilder builder = new ShadowDrawLooperBuilder();
for (BoxShadow boxShadow in shadows[1]) for (BoxShadow boxShadow in elevationToShadow[1])
builder.addShadow(boxShadow.offset, boxShadow.color, boxShadow.blur); builder.addShadow(boxShadow.offset, boxShadow.color, boxShadow.blurRadius);
paint.drawLooper = builder.build(); paint.drawLooper = builder.build();
// The thumb contracts slightly during the animation // The thumb contracts slightly during the animation
......
...@@ -18,7 +18,7 @@ class ToolBar extends StatelessComponent { ...@@ -18,7 +18,7 @@ class ToolBar extends StatelessComponent {
this.center, this.center,
this.right, this.right,
this.bottom, this.bottom,
this.level: 2, this.elevation: 4,
this.backgroundColor, this.backgroundColor,
this.textTheme, this.textTheme,
this.padding: EdgeDims.zero this.padding: EdgeDims.zero
...@@ -28,7 +28,7 @@ class ToolBar extends StatelessComponent { ...@@ -28,7 +28,7 @@ class ToolBar extends StatelessComponent {
final Widget center; final Widget center;
final List<Widget> right; final List<Widget> right;
final Widget bottom; final Widget bottom;
final int level; final int elevation;
final Color backgroundColor; final Color backgroundColor;
final TextTheme textTheme; final TextTheme textTheme;
final EdgeDims padding; final EdgeDims padding;
...@@ -40,7 +40,7 @@ class ToolBar extends StatelessComponent { ...@@ -40,7 +40,7 @@ class ToolBar extends StatelessComponent {
center: center, center: center,
right: right, right: right,
bottom: bottom, bottom: bottom,
level: level, elevation: elevation,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
textTheme: textTheme, textTheme: textTheme,
padding: newPadding padding: newPadding
...@@ -95,7 +95,7 @@ class ToolBar extends StatelessComponent { ...@@ -95,7 +95,7 @@ class ToolBar extends StatelessComponent {
padding: new EdgeDims.symmetric(horizontal: 8.0), padding: new EdgeDims.symmetric(horizontal: 8.0),
decoration: new BoxDecoration( decoration: new BoxDecoration(
backgroundColor: color, backgroundColor: color,
boxShadow: level == 0 ? null : shadows[2] boxShadow: elevationToShadow[elevation]
), ),
child: new DefaultTextStyle( child: new DefaultTextStyle(
style: sideStyle, style: sideStyle,
......
...@@ -8,7 +8,6 @@ import 'dart:ui' as ui; ...@@ -8,7 +8,6 @@ import 'dart:ui' as ui;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'basic_types.dart'; import 'basic_types.dart';
import 'shadows.dart';
/// An immutable set of offsets in each of the four cardinal directions. /// An immutable set of offsets in each of the four cardinal directions.
/// ///
...@@ -253,11 +252,13 @@ class Border { ...@@ -253,11 +252,13 @@ class Border {
/// ///
/// Note: BoxShadow can cast non-rectangular shadows if the box is /// Note: BoxShadow can cast non-rectangular shadows if the box is
/// non-rectangular (e.g., has a border radius or a circular shape). /// non-rectangular (e.g., has a border radius or a circular shape).
/// This class is similar to CSS box-shadow.
class BoxShadow { class BoxShadow {
const BoxShadow({ const BoxShadow({
this.color, this.color,
this.offset, this.offset,
this.blur this.blurRadius,
this.spreadRadius: 0.0
}); });
/// The color of the shadow /// The color of the shadow
...@@ -267,14 +268,20 @@ class BoxShadow { ...@@ -267,14 +268,20 @@ class BoxShadow {
final Offset offset; final Offset offset;
/// The standard deviation of the Gaussian to convolve with the box's shape /// The standard deviation of the Gaussian to convolve with the box's shape
final double blur; final double blurRadius;
/// Returns a new box shadow with its offset and blur scaled by the given factor final double spreadRadius;
// See SkBlurMask::ConvertRadiusToSigma()
double get _blurSigma => blurRadius * 0.57735 + 0.5;
/// Returns a new box shadow with its offset, blurRadius, and spreadRadius scaled by the given factor
BoxShadow scale(double factor) { BoxShadow scale(double factor) {
return new BoxShadow( return new BoxShadow(
color: color, color: color,
offset: offset * factor, offset: offset * factor,
blur: blur * factor blurRadius: blurRadius * factor,
spreadRadius: spreadRadius * factor
); );
} }
...@@ -282,7 +289,7 @@ class BoxShadow { ...@@ -282,7 +289,7 @@ class BoxShadow {
/// ///
/// If either box shadow is null, this function linearly interpolates from a /// If either box shadow is null, this function linearly interpolates from a
/// a box shadow that matches the other box shadow in color but has a zero /// a box shadow that matches the other box shadow in color but has a zero
/// offset and a zero blur. /// offset and a zero blurRadius.
static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) { static BoxShadow lerp(BoxShadow a, BoxShadow b, double t) {
if (a == null && b == null) if (a == null && b == null)
return null; return null;
...@@ -293,7 +300,8 @@ class BoxShadow { ...@@ -293,7 +300,8 @@ class BoxShadow {
return new BoxShadow( return new BoxShadow(
color: Color.lerp(a.color, b.color, t), color: Color.lerp(a.color, b.color, t),
offset: Offset.lerp(a.offset, b.offset, t), offset: Offset.lerp(a.offset, b.offset, t),
blur: ui.lerpDouble(a.blur, b.blur, t) blurRadius: ui.lerpDouble(a.blurRadius, b.blurRadius, t),
spreadRadius: ui.lerpDouble(a.spreadRadius, b.spreadRadius, t)
); );
} }
...@@ -326,18 +334,20 @@ class BoxShadow { ...@@ -326,18 +334,20 @@ class BoxShadow {
final BoxShadow typedOther = other; final BoxShadow typedOther = other;
return color == typedOther.color && return color == typedOther.color &&
offset == typedOther.offset && offset == typedOther.offset &&
blur == typedOther.blur; blurRadius == typedOther.blurRadius &&
spreadRadius == typedOther.spreadRadius;
} }
int get hashCode { int get hashCode {
int value = 373; int value = 373;
value = 37 * value + color.hashCode; value = 37 * value + color.hashCode;
value = 37 * value + offset.hashCode; value = 37 * value + offset.hashCode;
value = 37 * value + blur.hashCode; value = 37 * value + blurRadius.hashCode;
value = 37 * value + spreadRadius.hashCode;
return value; return value;
} }
String toString() => 'BoxShadow($color, $offset, $blur)'; String toString() => 'BoxShadow($color, $offset, $blurRadius, $spreadRadius)';
} }
/// A 2D gradient /// A 2D gradient
...@@ -894,13 +904,6 @@ class BoxPainter { ...@@ -894,13 +904,6 @@ class BoxPainter {
if (_decoration.backgroundColor != null) if (_decoration.backgroundColor != null)
paint.color = _decoration.backgroundColor; paint.color = _decoration.backgroundColor;
if (_decoration.boxShadow != null) {
var builder = new ShadowDrawLooperBuilder();
for (BoxShadow boxShadow in _decoration.boxShadow)
builder.addShadow(boxShadow.offset, boxShadow.color, boxShadow.blur);
paint.drawLooper = builder.build();
}
if (_decoration.gradient != null) if (_decoration.gradient != null)
paint.shader = _decoration.gradient.createShader(); paint.shader = _decoration.gradient.createShader();
...@@ -937,29 +940,42 @@ class BoxPainter { ...@@ -937,29 +940,42 @@ class BoxPainter {
return _decoration.borderRadius > shortestSide ? shortestSide : _decoration.borderRadius; return _decoration.borderRadius > shortestSide ? shortestSide : _decoration.borderRadius;
} }
void _paintBackgroundColor(ui.Canvas canvas, Rect rect) { void _paintBox(ui.Canvas canvas, Rect rect, Paint paint) {
if (_decoration.backgroundColor != null || switch (_decoration.shape) {
_decoration.boxShadow != null || case Shape.circle:
_decoration.gradient != null) { assert(_decoration.borderRadius == null);
switch (_decoration.shape) { Point center = rect.center;
case Shape.circle: double radius = rect.shortestSide / 2.0;
assert(_decoration.borderRadius == null); canvas.drawCircle(center, radius, paint);
Point center = rect.center; break;
double radius = rect.shortestSide / 2.0; case Shape.rectangle:
canvas.drawCircle(center, radius, _backgroundPaint); if (_decoration.borderRadius == null) {
break; canvas.drawRect(rect, paint);
case Shape.rectangle: } else {
if (_decoration.borderRadius == null) { double radius = _getEffectiveBorderRadius(rect);
canvas.drawRect(rect, _backgroundPaint); canvas.drawRRect(new ui.RRect.fromRectXY(rect, radius, radius), paint);
} else { }
double radius = _getEffectiveBorderRadius(rect); break;
canvas.drawRRect(new ui.RRect.fromRectXY(rect, radius, radius), _backgroundPaint);
}
break;
}
} }
} }
void _paintShadows(ui.Canvas canvas, Rect rect) {
if (_decoration.boxShadow == null)
return;
for (BoxShadow boxShadow in _decoration.boxShadow) {
final Paint paint = new Paint()
..color = boxShadow.color
..maskFilter = new ui.MaskFilter.blur(ui.BlurStyle.normal, boxShadow._blurSigma);
final Rect bounds = rect.shift(boxShadow.offset).inflate(boxShadow.spreadRadius);
_paintBox(canvas, bounds, paint);
}
}
void _paintBackgroundColor(ui.Canvas canvas, Rect rect) {
if (_decoration.backgroundColor != null || _decoration.gradient != null)
_paintBox(canvas, rect, _backgroundPaint);
}
void _paintBackgroundImage(ui.Canvas canvas, Rect rect) { void _paintBackgroundImage(ui.Canvas canvas, Rect rect) {
final BackgroundImage backgroundImage = _decoration.backgroundImage; final BackgroundImage backgroundImage = _decoration.backgroundImage;
if (backgroundImage == null) if (backgroundImage == null)
...@@ -1071,6 +1087,7 @@ class BoxPainter { ...@@ -1071,6 +1087,7 @@ class BoxPainter {
/// Paint the box decoration into the given location on the given canvas /// Paint the box decoration into the given location on the given canvas
void paint(ui.Canvas canvas, Rect rect) { void paint(ui.Canvas canvas, Rect rect) {
_paintShadows(canvas, rect);
_paintBackgroundColor(canvas, rect); _paintBackgroundColor(canvas, rect);
_paintBackgroundImage(canvas, rect); _paintBackgroundImage(canvas, rect);
_paintBorder(canvas, rect); _paintBorder(canvas, rect);
......
...@@ -12,7 +12,7 @@ void main() { ...@@ -12,7 +12,7 @@ void main() {
gradient: new RadialGradient( gradient: new RadialGradient(
center: Point.origin, radius: 500.0, center: Point.origin, radius: 500.0,
colors: <Color>[Colors.yellow[500], Colors.blue[500]]), colors: <Color>[Colors.yellow[500], Colors.blue[500]]),
boxShadow: shadows[3]) boxShadow: elevationToShadow[3])
); );
layout(root); layout(root);
expect(root.size.width, equals(800.0)); expect(root.size.width, equals(800.0));
......
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