diff --git a/examples/layers/widgets/gestures.dart b/examples/layers/widgets/gestures.dart index 6534567f82e..0b456d80fc4 100644 --- a/examples/layers/widgets/gestures.dart +++ b/examples/layers/widgets/gestures.dart @@ -29,12 +29,16 @@ class _GesturePainter extends CustomPainter { Point center = (size.center(Point.origin).toOffset() * zoom + offset).toPoint(); double radius = size.width / 2.0 * zoom; Gradient gradient = new RadialGradient( - center: center, radius: radius, colors: forward ? [swatch[50], swatch[900]] : [swatch[900], swatch[50]] ); Paint paint = new Paint() - ..shader = gradient.createShader(); + ..shader = gradient.createShader(new Rect.fromLTWH( + center.x - radius, + center.y - radius, + radius * 2.0, + radius * 2.0 + )); canvas.drawCircle(center, radius, paint); } diff --git a/examples/material_gallery/lib/demo/weathers_demo.dart b/examples/material_gallery/lib/demo/weathers_demo.dart index 2613678bbc8..942255ed78d 100644 --- a/examples/material_gallery/lib/demo/weathers_demo.dart +++ b/examples/material_gallery/lib/demo/weathers_demo.dart @@ -276,14 +276,15 @@ class GradientNode extends NodeWithSize { void paint(Canvas canvas) { applyTransformForPivot(canvas); + Rect rect = Point.origin & size; Paint gradientPaint = new Paint()..shader = new LinearGradient( - begin: Point.origin, - end: new Point(0.0, size.height), + begin: const Offset(0.0, 0.0), + end: const Offset(0.0, 1.0), colors: [colorTop, colorBottom], stops: [0.0, 1.0] - ).createShader(); + ).createShader(rect); - canvas.drawRect(new Rect.fromLTWH(0.0, 0.0, size.width, size.height), gradientPaint); + canvas.drawRect(rect, gradientPaint); } } diff --git a/packages/flutter/lib/src/painting/box_painter.dart b/packages/flutter/lib/src/painting/box_painter.dart index 9f5cf286857..dce01dec121 100644 --- a/packages/flutter/lib/src/painting/box_painter.dart +++ b/packages/flutter/lib/src/painting/box_painter.dart @@ -235,27 +235,43 @@ class BoxShadow { String toString() => 'BoxShadow($color, $offset, $blurRadius, $spreadRadius)'; } +// TODO(ianh): We should probably expose something that does this on Rect. +// https://github.com/flutter/flutter/issues/2318 +Point _offsetToPoint(Offset offset, Rect rect) { + return new Point(rect.left + offset.dx * rect.width, rect.top + offset.dy * rect.height); +} + /// A 2D gradient. abstract class Gradient { const Gradient(); - Shader createShader(); + Shader createShader(Rect rect); } /// A 2D linear gradient. class LinearGradient extends Gradient { const LinearGradient({ - this.begin, - this.end, + this.begin: const Offset(0.0, 0.5), + this.end: const Offset(1.0, 0.5), this.colors, this.stops, this.tileMode: TileMode.clamp }); - /// The point at which stop 0.0 of the gradient is placed. - final Point begin; + /// The offset from coordinate (0.0,0.0) at which stop 0.0 of the + /// gradient is placed, in a coordinate space that maps the top left + /// of the paint box at (0.0,0.0) and the bottom right at (1.0,1.0). + /// + /// For example, a begin offset of (0.0,0.5) is half way down the + /// left side of the box. + final Offset begin; - /// The point at which stop 1.0 of the gradient is placed. - final Point end; + /// The offset from coordinate (0.0,0.0) at which stop 1.0 of the + /// gradient is placed, in a coordinate space that maps the top left + /// of the paint box at (0.0,0.0) and the bottom right at (1.0,1.0). + /// + /// For example, an end offset of (1.0,0.5) is half way down the + /// right side of the box. + final Offset end; /// The colors the gradient should obtain at each of the stops. /// @@ -271,8 +287,11 @@ class LinearGradient extends Gradient { /// How this gradient should tile the plane. final TileMode tileMode; - Shader createShader() { - return new ui.Gradient.linear([begin, end], this.colors, this.stops, this.tileMode); + Shader createShader(Rect rect) { + return new ui.Gradient.linear( + [_offsetToPoint(begin, rect), _offsetToPoint(end, rect)], + colors, stops, tileMode + ); } bool operator ==(dynamic other) { @@ -316,17 +335,26 @@ class LinearGradient extends Gradient { /// A 2D radial gradient. class RadialGradient extends Gradient { const RadialGradient({ - this.center, - this.radius, + this.center: const Offset(0.5, 0.5), + this.radius: 0.5, this.colors, this.stops, this.tileMode: TileMode.clamp }); - /// The center of the gradient. - final Point center; + /// The center of the gradient, as an offset into the unit square + /// describing the gradient which will be mapped onto the paint box. + /// + /// For example, an offset of (0.5,0.5) will place the radial + /// gradient in the center of the box. + final Offset center; - /// The radius at which stop 1.0 is placed. + /// The radius of the gradient, as a fraction of the shortest side + /// of the paint box. + /// + /// For example, if a radial gradient is painted on a box that is + /// 100.0 pixels wide and 200.0 pixels tall, then a radius of 1.0 + /// will place the 1.0 stop at 100.0 pixels from the [center]. final double radius; /// The colors the gradient should obtain at each of the stops. @@ -345,8 +373,12 @@ class RadialGradient extends Gradient { /// How this gradient should tile the plane. final TileMode tileMode; - Shader createShader() { - return new ui.Gradient.radial(center, radius, colors, stops, tileMode); + Shader createShader(Rect rect) { + return new ui.Gradient.radial( + _offsetToPoint(center, rect), + radius * rect.shortestSide, + colors, stops, tileMode + ); } bool operator ==(dynamic other) { @@ -903,15 +935,23 @@ class _BoxDecorationPainter extends BoxPainter { final BoxDecoration _decoration; Paint _cachedBackgroundPaint; - Paint get _backgroundPaint { - if (_cachedBackgroundPaint == null) { + Rect _rectForCachedBackgroundPaint; + Paint _getBackgroundPaint(Rect rect) { + assert(rect != null); + if (_cachedBackgroundPaint == null || + (_decoration.gradient == null && _rectForCachedBackgroundPaint != null) || + (_decoration.gradient != null && _rectForCachedBackgroundPaint != rect)) { Paint paint = new Paint(); if (_decoration.backgroundColor != null) paint.color = _decoration.backgroundColor; - if (_decoration.gradient != null) - paint.shader = _decoration.gradient.createShader(); + if (_decoration.gradient != null) { + paint.shader = _decoration.gradient.createShader(rect); + _rectForCachedBackgroundPaint = rect; + } else { + _rectForCachedBackgroundPaint = null; + } _cachedBackgroundPaint = paint; } @@ -971,7 +1011,7 @@ class _BoxDecorationPainter extends BoxPainter { void _paintBackgroundColor(Canvas canvas, Rect rect) { if (_decoration.backgroundColor != null || _decoration.gradient != null) - _paintBox(canvas, rect, _backgroundPaint); + _paintBox(canvas, rect, _getBackgroundPaint(rect)); } void _paintBackgroundImage(Canvas canvas, Rect rect) { diff --git a/packages/flutter/test/rendering/box_test.dart b/packages/flutter/test/rendering/box_test.dart index 0fcda753057..7c42c4cef38 100644 --- a/packages/flutter/test/rendering/box_test.dart +++ b/packages/flutter/test/rendering/box_test.dart @@ -14,7 +14,7 @@ void main() { decoration: new BoxDecoration( backgroundColor: const Color(0xFF00FF00), gradient: new RadialGradient( - center: Point.origin, radius: 500.0, + center: Offset.zero, radius: 1.8, colors: [Colors.yellow[500], Colors.blue[500]]), boxShadow: elevationToShadow[3]) ); diff --git a/packages/flutter/test/widget/shader_mask_test.dart b/packages/flutter/test/widget/shader_mask_test.dart index 72a1df73133..b65b3088e31 100644 --- a/packages/flutter/test/widget/shader_mask_test.dart +++ b/packages/flutter/test/widget/shader_mask_test.dart @@ -10,12 +10,12 @@ import 'package:test/test.dart'; Shader createShader(Rect bounds) { return new LinearGradient( - begin: bounds.topLeft, - end: bounds.bottomLeft, + begin: const Offset(0.0, 0.0), + end: const Offset(0.0, 1.0), colors: [const Color(0x00FFFFFF), const Color(0xFFFFFFFF)], stops: [0.1, 0.35] ) - .createShader(); + .createShader(bounds); }