mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge pull request #1675 from Hixie/AnimatedContainer-overanimate
Stop AnimatedContainer from animating every build
This commit is contained in:
commit
8cd323cc5c
@ -30,6 +30,8 @@ class Scheduler {
|
||||
Map<int, SchedulerCallback> _transientCallbacks = new LinkedHashMap<int, SchedulerCallback>();
|
||||
final Set<int> _removedIds = new Set<int>();
|
||||
|
||||
int get transientCallbackCount => _transientCallbacks.length;
|
||||
|
||||
/// Called by the engine to produce a new frame.
|
||||
///
|
||||
/// This function first calls all the callbacks registered by
|
||||
|
||||
@ -51,7 +51,7 @@ class EdgeDims {
|
||||
/// The size that this edge dims would occupy with an empty interior.
|
||||
Size get collapsedSize => new Size(left + right, top + bottom);
|
||||
|
||||
EdgeDims operator-(EdgeDims other) {
|
||||
EdgeDims operator -(EdgeDims other) {
|
||||
return new EdgeDims.TRBL(
|
||||
top - other.top,
|
||||
right - other.right,
|
||||
@ -60,7 +60,7 @@ class EdgeDims {
|
||||
);
|
||||
}
|
||||
|
||||
EdgeDims operator+(EdgeDims other) {
|
||||
EdgeDims operator +(EdgeDims other) {
|
||||
return new EdgeDims.TRBL(
|
||||
top + other.top,
|
||||
right + other.right,
|
||||
@ -69,7 +69,7 @@ class EdgeDims {
|
||||
);
|
||||
}
|
||||
|
||||
EdgeDims operator*(double other) {
|
||||
EdgeDims operator *(double other) {
|
||||
return new EdgeDims.TRBL(
|
||||
top * other,
|
||||
right * other,
|
||||
@ -78,7 +78,7 @@ class EdgeDims {
|
||||
);
|
||||
}
|
||||
|
||||
EdgeDims operator/(double other) {
|
||||
EdgeDims operator /(double other) {
|
||||
return new EdgeDims.TRBL(
|
||||
top / other,
|
||||
right / other,
|
||||
@ -87,7 +87,7 @@ class EdgeDims {
|
||||
);
|
||||
}
|
||||
|
||||
EdgeDims operator~/(double other) {
|
||||
EdgeDims operator ~/(double other) {
|
||||
return new EdgeDims.TRBL(
|
||||
(top ~/ other).toDouble(),
|
||||
(right ~/ other).toDouble(),
|
||||
@ -96,7 +96,7 @@ class EdgeDims {
|
||||
);
|
||||
}
|
||||
|
||||
EdgeDims operator%(double other) {
|
||||
EdgeDims operator %(double other) {
|
||||
return new EdgeDims.TRBL(
|
||||
top % other,
|
||||
right % other,
|
||||
@ -166,12 +166,23 @@ class BorderSide {
|
||||
/// A black border side of zero width
|
||||
static const none = const BorderSide(width: 0.0);
|
||||
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other is! BorderSide)
|
||||
return false;
|
||||
final BorderSide typedOther = other;
|
||||
return color == typedOther.color &&
|
||||
width == typedOther.width;
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int value = 373;
|
||||
value = 37 * value * color.hashCode;
|
||||
value = 37 * value * width.hashCode;
|
||||
value = 37 * value + color.hashCode;
|
||||
value = 37 * value + width.hashCode;
|
||||
return value;
|
||||
}
|
||||
|
||||
String toString() => 'BorderSide($color, $width)';
|
||||
}
|
||||
|
||||
@ -210,14 +221,27 @@ class Border {
|
||||
return new EdgeDims.TRBL(top.width, right.width, bottom.width, left.width);
|
||||
}
|
||||
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other is! Border)
|
||||
return false;
|
||||
final Border typedOther = other;
|
||||
return top == typedOther.top &&
|
||||
right == typedOther.right &&
|
||||
bottom == typedOther.bottom &&
|
||||
left == typedOther.left;
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int value = 373;
|
||||
value = 37 * value * top.hashCode;
|
||||
value = 37 * value * right.hashCode;
|
||||
value = 37 * value * bottom.hashCode;
|
||||
value = 37 * value * left.hashCode;
|
||||
value = 37 * value + top.hashCode;
|
||||
value = 37 * value + right.hashCode;
|
||||
value = 37 * value + bottom.hashCode;
|
||||
value = 37 * value + left.hashCode;
|
||||
return value;
|
||||
}
|
||||
|
||||
String toString() => 'Border($top, $right, $bottom, $left)';
|
||||
}
|
||||
|
||||
@ -290,17 +314,37 @@ class BoxShadow {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other is! BoxShadow)
|
||||
return false;
|
||||
final BoxShadow typedOther = other;
|
||||
return color == typedOther.color &&
|
||||
offset == typedOther.offset &&
|
||||
blur == typedOther.blur;
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int value = 373;
|
||||
value = 37 * value + color.hashCode;
|
||||
value = 37 * value + offset.hashCode;
|
||||
value = 37 * value + blur.hashCode;
|
||||
return value;
|
||||
}
|
||||
|
||||
String toString() => 'BoxShadow($color, $offset, $blur)';
|
||||
}
|
||||
|
||||
/// A 2D gradient
|
||||
abstract class Gradient {
|
||||
const Gradient();
|
||||
ui.Shader createShader();
|
||||
}
|
||||
|
||||
/// A 2D linear gradient
|
||||
class LinearGradient extends Gradient {
|
||||
LinearGradient({
|
||||
const LinearGradient({
|
||||
this.begin,
|
||||
this.end,
|
||||
this.colors,
|
||||
@ -332,6 +376,57 @@ class LinearGradient extends Gradient {
|
||||
return new ui.Gradient.linear(<Point>[begin, end], this.colors, this.stops, this.tileMode);
|
||||
}
|
||||
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other is! LinearGradient)
|
||||
return false;
|
||||
final LinearGradient typedOther = other;
|
||||
if (begin != typedOther.begin ||
|
||||
end != typedOther.end ||
|
||||
tileMode != typedOther.tileMode ||
|
||||
colors?.length != typedOther.colors?.length ||
|
||||
stops?.length != typedOther.stops?.length)
|
||||
return false;
|
||||
if (colors != null) {
|
||||
assert(typedOther.colors != null);
|
||||
assert(colors.length == typedOther.colors.length);
|
||||
for (int i = 0; i < colors.length; i += 1) {
|
||||
if (colors[i] != typedOther.colors[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (stops != null) {
|
||||
assert(typedOther.stops != null);
|
||||
assert(stops.length == typedOther.stops.length);
|
||||
for (int i = 0; i < stops.length; i += 1) {
|
||||
if (stops[i] != typedOther.stops[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int value = 373;
|
||||
value = 37 * value + begin.hashCode;
|
||||
value = 37 * value + end.hashCode;
|
||||
value = 37 * value + tileMode.hashCode;
|
||||
if (colors != null) {
|
||||
for (int i = 0; i < colors.length; i += 1)
|
||||
value = 37 * value + colors[i].hashCode;
|
||||
} else {
|
||||
value = 37 * value + null.hashCode;
|
||||
}
|
||||
if (stops != null) {
|
||||
for (int i = 0; i < stops.length; i += 1)
|
||||
value = 37 * value + stops[i].hashCode;
|
||||
} else {
|
||||
value = 37 * value + null.hashCode;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
String toString() {
|
||||
return 'LinearGradient($begin, $end, $colors, $stops, $tileMode)';
|
||||
}
|
||||
@ -339,7 +434,7 @@ class LinearGradient extends Gradient {
|
||||
|
||||
/// A 2D radial gradient
|
||||
class RadialGradient extends Gradient {
|
||||
RadialGradient({
|
||||
const RadialGradient({
|
||||
this.center,
|
||||
this.radius,
|
||||
this.colors,
|
||||
@ -373,6 +468,57 @@ class RadialGradient extends Gradient {
|
||||
return new ui.Gradient.radial(center, radius, colors, stops, tileMode);
|
||||
}
|
||||
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other is! RadialGradient)
|
||||
return false;
|
||||
final RadialGradient typedOther = other;
|
||||
if (center != typedOther.center ||
|
||||
radius != typedOther.radius ||
|
||||
tileMode != typedOther.tileMode ||
|
||||
colors?.length != typedOther.colors?.length ||
|
||||
stops?.length != typedOther.stops?.length)
|
||||
return false;
|
||||
if (colors != null) {
|
||||
assert(typedOther.colors != null);
|
||||
assert(colors.length == typedOther.colors.length);
|
||||
for (int i = 0; i < colors.length; i += 1) {
|
||||
if (colors[i] != typedOther.colors[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (stops != null) {
|
||||
assert(typedOther.stops != null);
|
||||
assert(stops.length == typedOther.stops.length);
|
||||
for (int i = 0; i < stops.length; i += 1) {
|
||||
if (stops[i] != typedOther.stops[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int value = 373;
|
||||
value = 37 * value + center.hashCode;
|
||||
value = 37 * value + radius.hashCode;
|
||||
value = 37 * value + tileMode.hashCode;
|
||||
if (colors != null) {
|
||||
for (int i = 0; i < colors.length; i += 1)
|
||||
value = 37 * value + colors[i].hashCode;
|
||||
} else {
|
||||
value = 37 * value + null.hashCode;
|
||||
}
|
||||
if (stops != null) {
|
||||
for (int i = 0; i < stops.length; i += 1)
|
||||
value = 37 * value + stops[i].hashCode;
|
||||
} else {
|
||||
value = 37 * value + null.hashCode;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
String toString() {
|
||||
return 'RadialGradient($center, $radius, $colors, $stops, $tileMode)';
|
||||
}
|
||||
@ -498,6 +644,14 @@ typedef void BackgroundImageChangeListener();
|
||||
|
||||
/// A background image for a box.
|
||||
class BackgroundImage {
|
||||
BackgroundImage({
|
||||
ImageResource image,
|
||||
this.fit,
|
||||
this.repeat: ImageRepeat.noRepeat,
|
||||
this.centerSlice,
|
||||
this.colorFilter
|
||||
}) : _imageResource = image;
|
||||
|
||||
/// How the background image should be inscribed into the box.
|
||||
final ImageFit fit;
|
||||
|
||||
@ -516,22 +670,14 @@ class BackgroundImage {
|
||||
/// A color filter to apply to the background image before painting it.
|
||||
final ui.ColorFilter colorFilter;
|
||||
|
||||
BackgroundImage({
|
||||
ImageResource image,
|
||||
this.fit,
|
||||
this.repeat: ImageRepeat.noRepeat,
|
||||
this.centerSlice,
|
||||
this.colorFilter
|
||||
}) : _imageResource = image;
|
||||
|
||||
/// The image to be painted into the background.
|
||||
ui.Image get image => _image;
|
||||
ui.Image _image;
|
||||
|
||||
ImageResource _imageResource;
|
||||
final ImageResource _imageResource;
|
||||
|
||||
final List<BackgroundImageChangeListener> _listeners =
|
||||
new List<BackgroundImageChangeListener>();
|
||||
new List<BackgroundImageChangeListener>();
|
||||
|
||||
/// Call listener when the background images changes (e.g., arrives from the network).
|
||||
void addChangeListener(BackgroundImageChangeListener listener) {
|
||||
@ -557,10 +703,32 @@ class BackgroundImage {
|
||||
return;
|
||||
_image = resolvedImage;
|
||||
final List<BackgroundImageChangeListener> localListeners =
|
||||
new List<BackgroundImageChangeListener>.from(_listeners);
|
||||
for (BackgroundImageChangeListener listener in localListeners) {
|
||||
new List<BackgroundImageChangeListener>.from(_listeners);
|
||||
for (BackgroundImageChangeListener listener in localListeners)
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other is! BackgroundImage)
|
||||
return false;
|
||||
final BackgroundImage typedOther = other;
|
||||
return fit == typedOther.fit &&
|
||||
repeat == typedOther.repeat &&
|
||||
centerSlice == typedOther.centerSlice &&
|
||||
colorFilter == typedOther.colorFilter &&
|
||||
_imageResource == typedOther._imageResource;
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int value = 373;
|
||||
value = 37 * value + fit.hashCode;
|
||||
value = 37 * value + repeat.hashCode;
|
||||
value = 37 * value + centerSlice.hashCode;
|
||||
value = 37 * value + colorFilter.hashCode;
|
||||
value = 37 * value + _imageResource.hashCode;
|
||||
return value;
|
||||
}
|
||||
|
||||
String toString() => 'BackgroundImage($fit, $repeat)';
|
||||
@ -650,6 +818,33 @@ class BoxDecoration {
|
||||
);
|
||||
}
|
||||
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other is! BoxDecoration)
|
||||
return false;
|
||||
final BoxDecoration typedOther = other;
|
||||
return backgroundColor == typedOther.backgroundColor &&
|
||||
backgroundImage == typedOther.backgroundImage &&
|
||||
border == typedOther.border &&
|
||||
borderRadius == typedOther.borderRadius &&
|
||||
boxShadow == typedOther.boxShadow &&
|
||||
gradient == typedOther.gradient &&
|
||||
shape == typedOther.shape;
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
int value = 373;
|
||||
value = 37 * value + backgroundColor.hashCode;
|
||||
value = 37 * value + backgroundImage.hashCode;
|
||||
value = 37 * value + border.hashCode;
|
||||
value = 37 * value + borderRadius.hashCode;
|
||||
value = 37 * value + boxShadow.hashCode;
|
||||
value = 37 * value + gradient.hashCode;
|
||||
value = 37 * value + shape.hashCode;
|
||||
return value;
|
||||
}
|
||||
|
||||
String toString([String prefix = '']) {
|
||||
List<String> result = <String>[];
|
||||
if (backgroundColor != null)
|
||||
|
||||
@ -66,6 +66,7 @@ class AnimatedContainer extends StatefulComponent {
|
||||
}
|
||||
|
||||
final Widget child;
|
||||
|
||||
final BoxConstraints constraints;
|
||||
final BoxDecoration decoration;
|
||||
final BoxDecoration foregroundDecoration;
|
||||
@ -95,7 +96,7 @@ class _AnimatedContainerState extends State<AnimatedContainer> {
|
||||
|
||||
void initState() {
|
||||
super.initState();
|
||||
_performance = new Performance(duration: config.duration)
|
||||
_performance = new Performance(duration: config.duration, debugLabel: '${config.toStringShort()}')
|
||||
..timing = new AnimationTiming(curve: config.curve)
|
||||
..addListener(_updateAllVariables);
|
||||
_configAllVariables();
|
||||
|
||||
@ -202,8 +202,12 @@ abstract class Widget {
|
||||
/// Inflates this configuration to a concrete instance.
|
||||
Element createElement();
|
||||
|
||||
String toStringShort() {
|
||||
return key == null ? '$runtimeType' : '$runtimeType-$key';
|
||||
}
|
||||
|
||||
String toString() {
|
||||
final String name = key == null ? '$runtimeType' : '$runtimeType-$key';
|
||||
final String name = toStringShort();
|
||||
final List<String> data = <String>[];
|
||||
debugFillDescription(data);
|
||||
if (data.isEmpty)
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -45,4 +46,51 @@ void main() {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
test('AnimatedContainer overanimate test', () {
|
||||
testWidgets((WidgetTester tester) {
|
||||
tester.pumpWidget(
|
||||
new AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: new Color(0xFF00FF00)
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
tester.pump(new Duration(seconds: 1));
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
tester.pumpWidget(
|
||||
new AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: new Color(0xFF00FF00)
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
tester.pump(new Duration(seconds: 1));
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
tester.pumpWidget(
|
||||
new AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: new Color(0xFF0000FF)
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 1); // this is the only time an animation should have started!
|
||||
tester.pump(new Duration(seconds: 1));
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
tester.pumpWidget(
|
||||
new AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: new Color(0xFF0000FF)
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(scheduler.transientCallbackCount, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user