BoxDecoration tweaks (#12336)
Reorder the code, remove some redundant documentation, improve the interpolation logic.
This commit is contained in:
parent
53194ed477
commit
7d75c29b3b
@ -71,6 +71,8 @@ class BoxDecoration extends Decoration {
|
|||||||
/// [BoxShape.circle].
|
/// [BoxShape.circle].
|
||||||
/// * If [boxShadow] is null, this decoration does not paint a shadow.
|
/// * If [boxShadow] is null, this decoration does not paint a shadow.
|
||||||
/// * If [gradient] is null, this decoration does not paint gradients.
|
/// * If [gradient] is null, this decoration does not paint gradients.
|
||||||
|
///
|
||||||
|
/// The [shape] argument must not be null.
|
||||||
const BoxDecoration({
|
const BoxDecoration({
|
||||||
this.color,
|
this.color,
|
||||||
this.image,
|
this.image,
|
||||||
@ -79,7 +81,7 @@ class BoxDecoration extends Decoration {
|
|||||||
this.boxShadow,
|
this.boxShadow,
|
||||||
this.gradient,
|
this.gradient,
|
||||||
this.shape: BoxShape.rectangle,
|
this.shape: BoxShape.rectangle,
|
||||||
});
|
}) : assert(shape != null);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool debugAssertIsValid() {
|
bool debugAssertIsValid() {
|
||||||
@ -90,20 +92,30 @@ class BoxDecoration extends Decoration {
|
|||||||
|
|
||||||
/// The color to fill in the background of the box.
|
/// The color to fill in the background of the box.
|
||||||
///
|
///
|
||||||
/// The color is filled into the shape of the box (e.g., either a rectangle,
|
/// The color is filled into the [shape] of the box (e.g., either a rectangle,
|
||||||
/// potentially with a border radius, or a circle).
|
/// potentially with a [borderRadius], or a circle).
|
||||||
|
///
|
||||||
|
/// This is ignored if [gradient] is non-null.
|
||||||
|
///
|
||||||
|
/// The [color] is drawn under the [image].
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
/// An image to paint above the background color. If [shape] is [BoxShape.circle]
|
/// An image to paint above the background [color] or [gradient].
|
||||||
/// then the image is clipped to the circle's boundary.
|
///
|
||||||
|
/// If [shape] is [BoxShape.circle] then the image is clipped to the circle's
|
||||||
|
/// boundary; if [borderRadius] is non-null then the image is clipped to the
|
||||||
|
/// given radii.
|
||||||
final DecorationImage image;
|
final DecorationImage image;
|
||||||
|
|
||||||
/// A border to draw above the background [color] or [image].
|
/// A border to draw above the background [color], [gradient], or [image].
|
||||||
|
///
|
||||||
|
/// Follows the [shape] and [borderRadius].
|
||||||
final Border border;
|
final Border border;
|
||||||
|
|
||||||
/// If non-null, the corners of this box are rounded by this [BorderRadius].
|
/// If non-null, the corners of this box are rounded by this [BorderRadius].
|
||||||
///
|
///
|
||||||
/// Applies only to boxes with rectangular shapes.
|
/// Applies only to boxes with rectangular shapes; ignored if [shape] is not
|
||||||
|
/// [BoxShape.rectangle].
|
||||||
final BorderRadius borderRadius;
|
final BorderRadius borderRadius;
|
||||||
|
|
||||||
/// A list of shadows cast by this box behind the box.
|
/// A list of shadows cast by this box behind the box.
|
||||||
@ -112,12 +124,18 @@ class BoxDecoration extends Decoration {
|
|||||||
final List<BoxShadow> boxShadow;
|
final List<BoxShadow> boxShadow;
|
||||||
|
|
||||||
/// A gradient to use when filling the box.
|
/// A gradient to use when filling the box.
|
||||||
|
///
|
||||||
|
/// If this is specified, [color] has no effect.
|
||||||
|
///
|
||||||
|
/// The [gradient] is drawn under the [image].
|
||||||
final Gradient gradient;
|
final Gradient gradient;
|
||||||
|
|
||||||
/// The shape to fill the background [color] into and to cast as the [boxShadow].
|
/// The shape to fill the background [color], [gradient], and [image] into and
|
||||||
|
/// to cast as the [boxShadow].
|
||||||
|
///
|
||||||
|
/// If this is [BoxShape.rectangle] then [borderRadius] is ignored.
|
||||||
final BoxShape shape;
|
final BoxShape shape;
|
||||||
|
|
||||||
/// The inset space occupied by the border.
|
|
||||||
@override
|
@override
|
||||||
EdgeInsets get padding => border?.dimensions;
|
EdgeInsets get padding => border?.dimensions;
|
||||||
|
|
||||||
@ -138,11 +156,31 @@ class BoxDecoration extends Decoration {
|
|||||||
@override
|
@override
|
||||||
bool get isComplex => boxShadow != null;
|
bool get isComplex => boxShadow != null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
BoxDecoration lerpFrom(Decoration a, double t) {
|
||||||
|
if (a is BoxDecoration)
|
||||||
|
return BoxDecoration.lerp(a, this, t);
|
||||||
|
return super.lerpFrom(a, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
BoxDecoration lerpTo(Decoration b, double t) {
|
||||||
|
if (b is BoxDecoration)
|
||||||
|
return BoxDecoration.lerp(this, b, t);
|
||||||
|
return super.lerpTo(b, t);
|
||||||
|
}
|
||||||
|
|
||||||
/// Linearly interpolate between two box decorations.
|
/// Linearly interpolate between two box decorations.
|
||||||
///
|
///
|
||||||
/// Interpolates each parameter of the box decoration separately.
|
/// Interpolates each parameter of the box decoration separately.
|
||||||
///
|
///
|
||||||
/// See also [Decoration.lerp].
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [Decoration.lerp], which can interpolate between any two types of
|
||||||
|
/// [Decoration]s, not just [BoxDecoration]s.
|
||||||
|
/// * [lerpFrom] and [lerpTo], which are used to implement [Decoration.lerp]
|
||||||
|
/// and which use [BoxDecoration.lerp] when interpolating two
|
||||||
|
/// [BoxDecoration]s or a [BoxDecoration] to or from null.
|
||||||
static BoxDecoration lerp(BoxDecoration a, BoxDecoration b, double t) {
|
static BoxDecoration lerp(BoxDecoration a, BoxDecoration b, double t) {
|
||||||
if (a == null && b == null)
|
if (a == null && b == null)
|
||||||
return null;
|
return null;
|
||||||
@ -153,29 +191,15 @@ class BoxDecoration extends Decoration {
|
|||||||
// TODO(abarth): lerp ALL the fields.
|
// TODO(abarth): lerp ALL the fields.
|
||||||
return new BoxDecoration(
|
return new BoxDecoration(
|
||||||
color: Color.lerp(a.color, b.color, t),
|
color: Color.lerp(a.color, b.color, t),
|
||||||
image: b.image,
|
image: t < 0.5 ? a.image : b.image,
|
||||||
border: Border.lerp(a.border, b.border, t),
|
border: Border.lerp(a.border, b.border, t),
|
||||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||||
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
||||||
gradient: b.gradient,
|
gradient: t < 0.5 ? a.gradient : b.gradient,
|
||||||
shape: b.shape,
|
shape: t < 0.5 ? a.shape : b.shape,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
BoxDecoration lerpFrom(Decoration a, double t) {
|
|
||||||
if (a is! BoxDecoration)
|
|
||||||
return BoxDecoration.lerp(null, this, t);
|
|
||||||
return BoxDecoration.lerp(a, this, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
BoxDecoration lerpTo(Decoration b, double t) {
|
|
||||||
if (b is! BoxDecoration)
|
|
||||||
return BoxDecoration.lerp(this, null, t);
|
|
||||||
return BoxDecoration.lerp(this, b, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
if (identical(this, other))
|
if (identical(this, other))
|
||||||
@ -261,21 +285,17 @@ class _BoxDecorationPainter extends BoxPainter {
|
|||||||
Rect _rectForCachedBackgroundPaint;
|
Rect _rectForCachedBackgroundPaint;
|
||||||
Paint _getBackgroundPaint(Rect rect) {
|
Paint _getBackgroundPaint(Rect rect) {
|
||||||
assert(rect != null);
|
assert(rect != null);
|
||||||
|
assert(_decoration.gradient != null || _rectForCachedBackgroundPaint == null);
|
||||||
|
|
||||||
if (_cachedBackgroundPaint == null ||
|
if (_cachedBackgroundPaint == null ||
|
||||||
(_decoration.gradient == null && _rectForCachedBackgroundPaint != null) ||
|
|
||||||
(_decoration.gradient != null && _rectForCachedBackgroundPaint != rect)) {
|
(_decoration.gradient != null && _rectForCachedBackgroundPaint != rect)) {
|
||||||
final Paint paint = new Paint();
|
final Paint paint = new Paint();
|
||||||
|
|
||||||
if (_decoration.color != null)
|
if (_decoration.color != null)
|
||||||
paint.color = _decoration.color;
|
paint.color = _decoration.color;
|
||||||
|
|
||||||
if (_decoration.gradient != null) {
|
if (_decoration.gradient != null) {
|
||||||
paint.shader = _decoration.gradient.createShader(rect);
|
paint.shader = _decoration.gradient.createShader(rect);
|
||||||
_rectForCachedBackgroundPaint = rect;
|
_rectForCachedBackgroundPaint = rect;
|
||||||
} else {
|
|
||||||
_rectForCachedBackgroundPaint = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cachedBackgroundPaint = paint;
|
_cachedBackgroundPaint = paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,8 @@ void main() {
|
|||||||
// Regression test for https://github.com/flutter/flutter/issues/7289.
|
// Regression test for https://github.com/flutter/flutter/issues/7289.
|
||||||
// A reference test would be better.
|
// A reference test would be better.
|
||||||
test('BoxDecoration backgroundImage clip', () {
|
test('BoxDecoration backgroundImage clip', () {
|
||||||
void testDecoration({ BoxShape shape, BorderRadius borderRadius, bool expectClip}) {
|
void testDecoration({ BoxShape shape: BoxShape.rectangle, BorderRadius borderRadius, bool expectClip}) {
|
||||||
|
assert(shape != null);
|
||||||
new FakeAsync().run((FakeAsync async) {
|
new FakeAsync().run((FakeAsync async) {
|
||||||
final DelayedImageProvider imageProvider = new DelayedImageProvider();
|
final DelayedImageProvider imageProvider = new DelayedImageProvider();
|
||||||
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
||||||
@ -226,4 +227,110 @@ void main() {
|
|||||||
expect(call.positionalArguments[3].colorFilter, colorFilter);
|
expect(call.positionalArguments[3].colorFilter, colorFilter);
|
||||||
expect(call.positionalArguments[3].filterQuality, FilterQuality.low);
|
expect(call.positionalArguments[3].filterQuality, FilterQuality.low);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('BoxDecoration.lerp - shapes', () {
|
||||||
|
// We don't lerp the shape, we just switch from one to the other at t=0.5.
|
||||||
|
// (Use a ShapeDecoration and ShapeBorder if you want to lerp the shapes...)
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle),
|
||||||
|
-1.0,
|
||||||
|
),
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle),
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle),
|
||||||
|
0.25,
|
||||||
|
),
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle),
|
||||||
|
0.75,
|
||||||
|
),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle),
|
||||||
|
1.0,
|
||||||
|
),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(shape: BoxShape.rectangle),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle),
|
||||||
|
2.0,
|
||||||
|
),
|
||||||
|
const BoxDecoration(shape: BoxShape.circle)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('BoxDecoration.lerp - gradients', () {
|
||||||
|
// We don't lerp the gradients, we just switch from one to the other at t=0.5.
|
||||||
|
final Gradient gradient = new LinearGradient(colors: <Color>[ const Color(0x00000000), const Color(0xFFFFFFFF) ]);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(),
|
||||||
|
new BoxDecoration(gradient: gradient),
|
||||||
|
-1.0,
|
||||||
|
),
|
||||||
|
const BoxDecoration()
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(),
|
||||||
|
new BoxDecoration(gradient: gradient),
|
||||||
|
0.0,
|
||||||
|
),
|
||||||
|
const BoxDecoration()
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(),
|
||||||
|
new BoxDecoration(gradient: gradient),
|
||||||
|
0.25,
|
||||||
|
),
|
||||||
|
const BoxDecoration()
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(),
|
||||||
|
new BoxDecoration(gradient: gradient),
|
||||||
|
0.75,
|
||||||
|
),
|
||||||
|
new BoxDecoration(gradient: gradient)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(),
|
||||||
|
new BoxDecoration(gradient: gradient),
|
||||||
|
1.0,
|
||||||
|
),
|
||||||
|
new BoxDecoration(gradient: gradient)
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
BoxDecoration.lerp(
|
||||||
|
const BoxDecoration(),
|
||||||
|
new BoxDecoration(gradient: gradient),
|
||||||
|
2.0,
|
||||||
|
),
|
||||||
|
new BoxDecoration(gradient: gradient)
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user