[flutter] throw more specific error messages if a lerp'd type does not conform to Tween API (#74684)
This commit is contained in:
@@ -256,6 +256,51 @@ class Tween<T extends dynamic> extends Animatable<T> {
|
||||
T lerp(double t) {
|
||||
assert(begin != null);
|
||||
assert(end != null);
|
||||
assert(() {
|
||||
// Assertions that attempt to catch common cases of tweening types
|
||||
// that do not conform to the Tween requirements.
|
||||
dynamic? result;
|
||||
try {
|
||||
result = begin + (end - begin) * t;
|
||||
result as T;
|
||||
return true;
|
||||
} on NoSuchMethodError {
|
||||
throw FlutterError.fromParts(<DiagnosticsNode>[
|
||||
ErrorSummary('Cannot lerp between "$begin" and "$end".'),
|
||||
ErrorDescription(
|
||||
'The type ${begin.runtimeType} might not fully implement `+`, `-`, and/or `*`. '
|
||||
'See "Types with special considerations" at https://api.flutter.dev/flutter/animation/Tween-class.html '
|
||||
'for more information.',
|
||||
),
|
||||
if (begin is Color || end is Color)
|
||||
ErrorHint('To lerp colors, consider ColorTween instead.')
|
||||
else if (begin is Rect || end is Rect)
|
||||
ErrorHint('To lerp rects, consider RectTween instead.')
|
||||
else
|
||||
ErrorHint(
|
||||
'There may be a dedicated "${begin.runtimeType}Tween" for this type, '
|
||||
'or you may need to create one.'
|
||||
),
|
||||
]);
|
||||
} on TypeError {
|
||||
throw FlutterError.fromParts(<DiagnosticsNode>[
|
||||
ErrorSummary('Cannot lerp between "$begin" and "$end".'),
|
||||
ErrorDescription(
|
||||
'The type ${begin.runtimeType} returned a ${result.runtimeType} after '
|
||||
'multiplication with a double value. '
|
||||
'See "Types with special considerations" at https://api.flutter.dev/flutter/animation/Tween-class.html '
|
||||
'for more information.',
|
||||
),
|
||||
if (begin is int || end is int)
|
||||
ErrorHint('To lerp int values, consider IntTween or StepTween instead.')
|
||||
else
|
||||
ErrorHint(
|
||||
'There may be a dedicated "${begin.runtimeType}Tween" for this type, '
|
||||
'or you may need to create one.'
|
||||
),
|
||||
]);
|
||||
}
|
||||
}());
|
||||
return begin + (end - begin) * t as T;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,105 @@ import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
const String kApiDocsLink = 'See "Types with special considerations" at https://api.flutter.dev/flutter/animation/Tween-class.html for more information.';
|
||||
|
||||
void main() {
|
||||
test('throws flutter error when tweening types that do not fully satisfy tween requirements - Object', () {
|
||||
final Tween<Object> objectTween = Tween<Object>(
|
||||
begin: Object(),
|
||||
end: Object(),
|
||||
);
|
||||
|
||||
FlutterError? error;
|
||||
try {
|
||||
objectTween.transform(0.1);
|
||||
} on FlutterError catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
if (error == null) {
|
||||
fail('Expected Tween.transform to throw a FlutterError');
|
||||
}
|
||||
|
||||
expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
|
||||
'Cannot lerp between "Instance of \'Object\'" and "Instance of \'Object\'".',
|
||||
'The type Object might not fully implement `+`, `-`, and/or `*`. $kApiDocsLink',
|
||||
'There may be a dedicated "ObjectTween" for this type, or you may need to create one.'
|
||||
]);
|
||||
});
|
||||
|
||||
test('throws flutter error when tweening types that do not fully satisfy tween requirements - Color', () {
|
||||
final Tween<Color> colorTween = Tween<Color>(
|
||||
begin: const Color(0xFF000000),
|
||||
end: const Color(0xFFFFFFFF),
|
||||
);
|
||||
|
||||
FlutterError? error;
|
||||
try {
|
||||
colorTween.transform(0.1);
|
||||
} on FlutterError catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
if (error == null) {
|
||||
fail('Expected Tween.transform to throw a FlutterError');
|
||||
}
|
||||
|
||||
expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
|
||||
'Cannot lerp between "Color(0xff000000)" and "Color(0xffffffff)".',
|
||||
'The type Color might not fully implement `+`, `-`, and/or `*`. $kApiDocsLink',
|
||||
'To lerp colors, consider ColorTween instead.',
|
||||
]);
|
||||
});
|
||||
|
||||
test('throws flutter error when tweening types that do not fully satisfy tween requirements - Rect', () {
|
||||
final Tween<Rect> rectTween = Tween<Rect>(
|
||||
begin: const Rect.fromLTWH(0, 0, 10, 10),
|
||||
end: const Rect.fromLTWH(2, 2, 2, 2)
|
||||
);
|
||||
|
||||
FlutterError? error;
|
||||
try {
|
||||
rectTween.transform(0.1);
|
||||
} on FlutterError catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
if (error == null) {
|
||||
fail('Expected Tween.transform to throw a FlutterError');
|
||||
}
|
||||
|
||||
expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
|
||||
'Cannot lerp between "Rect.fromLTRB(0.0, 0.0, 10.0, 10.0)" and "Rect.fromLTRB(2.0, 2.0, 4.0, 4.0)".',
|
||||
'The type Rect might not fully implement `+`, `-`, and/or `*`. $kApiDocsLink',
|
||||
'To lerp rects, consider RectTween instead.',
|
||||
]);
|
||||
});
|
||||
|
||||
test('throws flutter error when tweening types that do not fully satisfy tween requirements - int', () {
|
||||
final Tween<int> colorTween = Tween<int>(
|
||||
begin: 0,
|
||||
end: 1,
|
||||
);
|
||||
|
||||
FlutterError? error;
|
||||
try {
|
||||
colorTween.transform(0.1);
|
||||
} on FlutterError catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
if (error == null) {
|
||||
fail('Expected Tween.transform to throw a FlutterError');
|
||||
}
|
||||
|
||||
expect(error.diagnostics.map((DiagnosticsNode node) => node.toString()), <String>[
|
||||
'Cannot lerp between "0" and "1".',
|
||||
'The type int returned a double after multiplication with a double value. $kApiDocsLink',
|
||||
'To lerp int values, consider IntTween or StepTween instead.',
|
||||
]);
|
||||
});
|
||||
|
||||
test('Can chain tweens', () {
|
||||
final Tween<double> tween = Tween<double>(begin: 0.30, end: 0.50);
|
||||
expect(tween, hasOneLineDescription);
|
||||
|
||||
Reference in New Issue
Block a user