Fix DecorationImage.centerSlice (#10257)
...and rearrange a bunch of code so that all these arguments/members are always in the same order.
This commit is contained in:
parent
61e938aa1e
commit
51ba6b377b
@ -1239,9 +1239,9 @@ void paintImage({
|
||||
@required ui.Image image,
|
||||
ColorFilter colorFilter,
|
||||
BoxFit fit,
|
||||
ImageRepeat repeat: ImageRepeat.noRepeat,
|
||||
FractionalOffset alignment,
|
||||
Rect centerSlice,
|
||||
FractionalOffset alignment
|
||||
ImageRepeat repeat: ImageRepeat.noRepeat,
|
||||
}) {
|
||||
assert(canvas != null);
|
||||
assert(image != null);
|
||||
@ -1266,7 +1266,7 @@ void paintImage({
|
||||
destinationSize += sliceBorder;
|
||||
// We don't have the ability to draw a subset of the image at the same time
|
||||
// as we apply a nine-patch stretch.
|
||||
assert(sourceSize == inputSize);
|
||||
assert(sourceSize == inputSize, 'centerSlice was used with a BoxFit that does not guarantee that the image is fully visible.');
|
||||
}
|
||||
if (repeat != ImageRepeat.noRepeat && destinationSize == outputSize) {
|
||||
// There's no need to repeat the image because we're exactly filling the
|
||||
@ -1315,11 +1315,11 @@ class DecorationImage {
|
||||
/// The [image] argument must not be null.
|
||||
const DecorationImage({
|
||||
@required this.image,
|
||||
this.fit,
|
||||
this.repeat: ImageRepeat.noRepeat,
|
||||
this.centerSlice,
|
||||
this.colorFilter,
|
||||
this.fit,
|
||||
this.alignment,
|
||||
this.centerSlice,
|
||||
this.repeat: ImageRepeat.noRepeat,
|
||||
}) : assert(image != null);
|
||||
|
||||
/// The image to be painted into the decoration.
|
||||
@ -1328,6 +1328,9 @@ class DecorationImage {
|
||||
/// application) or a [NetworkImage] (for an image obtained from the network).
|
||||
final ImageProvider image;
|
||||
|
||||
/// A color filter to apply to the image before painting it.
|
||||
final ColorFilter colorFilter;
|
||||
|
||||
/// How the image should be inscribed into the box.
|
||||
///
|
||||
/// The default is [BoxFit.scaleDown] if [centerSlice] is null, and
|
||||
@ -1336,9 +1339,14 @@ class DecorationImage {
|
||||
/// See the discussion at [paintImage] for more details.
|
||||
final BoxFit fit;
|
||||
|
||||
/// How to paint any portions of the box that would not otherwise be covered
|
||||
/// by the image.
|
||||
final ImageRepeat repeat;
|
||||
/// How to align the image within its bounds.
|
||||
///
|
||||
/// An alignment of (0.0, 0.0) aligns the image to the top-left corner of its
|
||||
/// layout bounds. An alignment of (1.0, 0.5) aligns the image to the middle
|
||||
/// of the right edge of its layout bounds.
|
||||
///
|
||||
/// Defaults to [FractionalOffset.center].
|
||||
final FractionalOffset alignment;
|
||||
|
||||
/// The center slice for a nine-patch image.
|
||||
///
|
||||
@ -1357,17 +1365,9 @@ class DecorationImage {
|
||||
/// scaling, as if it wasn't specified).
|
||||
final Rect centerSlice;
|
||||
|
||||
/// A color filter to apply to the image before painting it.
|
||||
final ColorFilter colorFilter;
|
||||
|
||||
/// How to align the image within its bounds.
|
||||
///
|
||||
/// An alignment of (0.0, 0.0) aligns the image to the top-left corner of its
|
||||
/// layout bounds. An alignment of (1.0, 0.5) aligns the image to the middle
|
||||
/// of the right edge of its layout bounds.
|
||||
///
|
||||
/// Defaults to [FractionalOffset.center].
|
||||
final FractionalOffset alignment;
|
||||
/// How to paint any portions of the box that would not otherwise be covered
|
||||
/// by the image.
|
||||
final ImageRepeat repeat;
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
@ -1376,19 +1376,35 @@ class DecorationImage {
|
||||
if (runtimeType != other.runtimeType)
|
||||
return false;
|
||||
final DecorationImage typedOther = other;
|
||||
return image == typedOther.image &&
|
||||
fit == typedOther.fit &&
|
||||
repeat == typedOther.repeat &&
|
||||
centerSlice == typedOther.centerSlice &&
|
||||
colorFilter == typedOther.colorFilter &&
|
||||
alignment == typedOther.alignment;
|
||||
return image == typedOther.image
|
||||
&& colorFilter == typedOther.colorFilter
|
||||
&& fit == typedOther.fit
|
||||
&& alignment == typedOther.alignment
|
||||
&& centerSlice == typedOther.centerSlice
|
||||
&& repeat == typedOther.repeat;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(image, fit, repeat, centerSlice, colorFilter, alignment);
|
||||
int get hashCode => hashValues(image, colorFilter, fit, alignment, centerSlice, repeat);
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType($image, $fit, $repeat)';
|
||||
String toString() {
|
||||
final List<String> properties = <String>[];
|
||||
properties.add('$image');
|
||||
if (colorFilter != null)
|
||||
properties.add('$colorFilter');
|
||||
if (fit != null &&
|
||||
!(fit == BoxFit.fill && centerSlice != null) &&
|
||||
!(fit == BoxFit.scaleDown && centerSlice == null))
|
||||
properties.add('$fit');
|
||||
if (alignment != null)
|
||||
properties.add('$alignment');
|
||||
if (centerSlice != null)
|
||||
properties.add('centerSlice: $centerSlice');
|
||||
if (repeat != ImageRepeat.noRepeat)
|
||||
properties.add('$repeat');
|
||||
return '$runtimeType(${properties.join(", ")})';
|
||||
}
|
||||
}
|
||||
|
||||
/// An immutable description of how to paint a box.
|
||||
@ -1452,7 +1468,7 @@ class BoxDecoration extends Decoration {
|
||||
this.borderRadius,
|
||||
this.boxShadow,
|
||||
this.gradient,
|
||||
this.shape: BoxShape.rectangle
|
||||
this.shape: BoxShape.rectangle,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -1505,7 +1521,7 @@ class BoxDecoration extends Decoration {
|
||||
borderRadius: BorderRadius.lerp(null, borderRadius, factor),
|
||||
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
|
||||
gradient: gradient,
|
||||
shape: shape
|
||||
shape: shape,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1532,7 +1548,7 @@ class BoxDecoration extends Decoration {
|
||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
|
||||
gradient: b.gradient,
|
||||
shape: b.shape
|
||||
shape: b.shape,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1575,7 +1591,7 @@ class BoxDecoration extends Decoration {
|
||||
borderRadius,
|
||||
boxShadow,
|
||||
gradient,
|
||||
shape
|
||||
shape,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1741,9 +1757,10 @@ class _BoxDecorationPainter extends BoxPainter {
|
||||
rect: rect,
|
||||
image: image,
|
||||
colorFilter: backgroundImage.colorFilter,
|
||||
alignment: backgroundImage.alignment,
|
||||
fit: backgroundImage.fit,
|
||||
repeat: backgroundImage.repeat
|
||||
alignment: backgroundImage.alignment,
|
||||
centerSlice: backgroundImage.centerSlice,
|
||||
repeat: backgroundImage.repeat,
|
||||
);
|
||||
|
||||
if (clipPath != null)
|
||||
|
@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui show Image;
|
||||
import 'dart:ui' as ui show Image, ColorFilter;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
@ -33,7 +33,7 @@ class SynchronousTestImageProvider extends ImageProvider<int> {
|
||||
@override
|
||||
ImageStreamCompleter load(int key) {
|
||||
return new OneFrameImageStreamCompleter(
|
||||
new SynchronousFuture<ImageInfo>(new TestImageInfo(key))
|
||||
new SynchronousFuture<ImageInfo>(new TestImageInfo(key, image: new TestImage(), scale: 1.0))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -90,7 +90,7 @@ class TestImage extends ui.Image {
|
||||
}
|
||||
|
||||
void main() {
|
||||
test("Decoration.lerp()", () {
|
||||
test('Decoration.lerp()', () {
|
||||
final BoxDecoration a = const BoxDecoration(color: const Color(0xFFFFFFFF));
|
||||
final BoxDecoration b = const BoxDecoration(color: const Color(0x00000000));
|
||||
|
||||
@ -104,7 +104,7 @@ void main() {
|
||||
expect(c.color, equals(b.color));
|
||||
});
|
||||
|
||||
test("BoxDecorationImageListenerSync", () {
|
||||
test('BoxDecorationImageListenerSync', () {
|
||||
final ImageProvider imageProvider = new SynchronousTestImageProvider();
|
||||
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
||||
|
||||
@ -122,7 +122,7 @@ void main() {
|
||||
expect(onChangedCalled, equals(false));
|
||||
});
|
||||
|
||||
test("BoxDecorationImageListenerAsync", () {
|
||||
test('BoxDecorationImageListenerAsync', () {
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
final ImageProvider imageProvider = new AsyncTestImageProvider();
|
||||
final DecorationImage backgroundImage = new DecorationImage(image: imageProvider);
|
||||
@ -146,7 +146,7 @@ void main() {
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/7289.
|
||||
// A reference test would be better.
|
||||
test("BoxDecoration backgroundImage clip", () {
|
||||
test('BoxDecoration backgroundImage clip', () {
|
||||
void testDecoration({ BoxShape shape, BorderRadius borderRadius, bool expectClip}) {
|
||||
new FakeAsync().run((FakeAsync async) {
|
||||
final DelayedImageProvider imageProvider = new DelayedImageProvider();
|
||||
@ -198,4 +198,32 @@ void main() {
|
||||
testDecoration(borderRadius: const BorderRadius.all(const Radius.circular(16.0)), expectClip: true);
|
||||
testDecoration(expectClip: false);
|
||||
});
|
||||
|
||||
test('DecorationImage test', () {
|
||||
final ColorFilter colorFilter = const ui.ColorFilter.mode(const Color(0xFF00FF00), BlendMode.src);
|
||||
final DecorationImage backgroundImage = new DecorationImage(
|
||||
image: new SynchronousTestImageProvider(),
|
||||
colorFilter: colorFilter,
|
||||
fit: BoxFit.contain,
|
||||
alignment: FractionalOffset.bottomLeft,
|
||||
centerSlice: new Rect.fromLTWH(10.0, 20.0, 30.0, 40.0),
|
||||
repeat: ImageRepeat.repeatY,
|
||||
);
|
||||
|
||||
final BoxDecoration boxDecoration = new BoxDecoration(image: backgroundImage);
|
||||
final BoxPainter boxPainter = boxDecoration.createBoxPainter(() { assert(false); });
|
||||
final TestCanvas canvas = new TestCanvas(<Invocation>[]);
|
||||
boxPainter.paint(canvas, Offset.zero, const ImageConfiguration(size: const Size(10.0, 10.0)));
|
||||
|
||||
final Invocation call = canvas.invocations.singleWhere((Invocation call) => call.memberName == #drawImageNine);
|
||||
expect(call.isMethod, isTrue);
|
||||
expect(call.positionalArguments, hasLength(4));
|
||||
expect(call.positionalArguments[0], const isInstanceOf<TestImage>());
|
||||
expect(call.positionalArguments[1], new Rect.fromLTRB(10.0, 20.0, 40.0, 60.0));
|
||||
expect(call.positionalArguments[2], new Rect.fromLTRB(0.0, 0.0, 32.5, 10.0));
|
||||
expect(call.positionalArguments[3], const isInstanceOf<Paint>());
|
||||
expect(call.positionalArguments[3].isAntiAlias, false);
|
||||
expect(call.positionalArguments[3].colorFilter, colorFilter);
|
||||
expect(call.positionalArguments[3].filterQuality, FilterQuality.low);
|
||||
});
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class TestCanvas implements Canvas {
|
||||
}
|
||||
|
||||
void main() {
|
||||
test("Cover and align", () {
|
||||
test('Cover and align', () {
|
||||
final TestImage image = new TestImage(width: 300, height: 300);
|
||||
final TestCanvas canvas = new TestCanvas();
|
||||
paintImage(
|
||||
@ -51,4 +51,6 @@ void main() {
|
||||
expect(command.positionalArguments[1], equals(new Rect.fromLTWH(0.0, 75.0, 300.0, 150.0)));
|
||||
expect(command.positionalArguments[2], equals(new Rect.fromLTWH(50.0, 75.0, 200.0, 100.0)));
|
||||
});
|
||||
|
||||
// See also the DecorationImage tests in: decoration_test.dart
|
||||
}
|
||||
|
@ -9,13 +9,13 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class TestImageInfo implements ImageInfo {
|
||||
const TestImageInfo(this.value) : image = null, scale = null;
|
||||
const TestImageInfo(this.value, { this.image, this.scale });
|
||||
|
||||
@override
|
||||
final ui.Image image; // ignored in test
|
||||
final ui.Image image;
|
||||
|
||||
@override
|
||||
final double scale; // ignored in test
|
||||
final double scale;
|
||||
|
||||
final int value;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user