diff --git a/packages/flutter/lib/src/painting/colors.dart b/packages/flutter/lib/src/painting/colors.dart index 60c81abfd3..c698cec3fe 100644 --- a/packages/flutter/lib/src/painting/colors.dart +++ b/packages/flutter/lib/src/painting/colors.dart @@ -457,6 +457,44 @@ class ColorSwatch extends Color { @override String toString() => '${objectRuntimeType(this, 'ColorSwatch')}(primary value: ${super.toString()})'; + + /// Linearly interpolate between two [ColorSwatch]es. + /// + /// It delegates to [Color.lerp] to interpolate the different colors of the + /// swatch. + /// + /// If either color is null, this function linearly interpolates from a + /// transparent instance of the other color. + /// + /// The `t` argument represents position on the timeline, with 0.0 meaning + /// that the interpolation has not started, returning `a` (or something + /// equivalent to `a`), 1.0 meaning that the interpolation has finished, + /// returning `b` (or something equivalent to `b`), and values in between + /// meaning that the interpolation is at the relevant point on the timeline + /// between `a` and `b`. The interpolation can be extrapolated beyond 0.0 and + /// 1.0, so negative values and values greater than 1.0 are valid (and can + /// easily be generated by curves such as [Curves.elasticInOut]). Each channel + /// will be clamped to the range 0 to 255. + /// + /// Values for `t` are usually obtained from an [Animation], such as + /// an [AnimationController]. + static ColorSwatch? lerp(ColorSwatch? a, ColorSwatch? b, double t) { + final Map swatch; + if (b == null) { + if (a == null) { + return null; + } else { + swatch = a._swatch.map((T key, Color color) => MapEntry(key, Color.lerp(color, null, t)!)); + } + } else { + if (a == null) { + swatch = b._swatch.map((T key, Color color) => MapEntry(key, Color.lerp(null, color, t)!)); + } else { + swatch = a._swatch.map((T key, Color color) => MapEntry(key, Color.lerp(color, b[key], t)!)); + } + } + return ColorSwatch(Color.lerp(a, b, t)!.value, swatch); + } } /// [DiagnosticsProperty] that has an [Color] as value. diff --git a/packages/flutter/test/painting/colors_test.dart b/packages/flutter/test/painting/colors_test.dart index 82c01274c7..8ea450d61e 100644 --- a/packages/flutter/test/painting/colors_test.dart +++ b/packages/flutter/test/painting/colors_test.dart @@ -426,6 +426,31 @@ void main() { expect(greens1.value, 0xFF027223); }); + test('ColorSwatch.lerp', () { + const ColorSwatch swatchA = ColorSwatch(0x00000000, {1: Color(0x00000000)}); + const ColorSwatch swatchB = ColorSwatch(0xFFFFFFFF, {1: Color(0xFFFFFFFF)}); + expect( + ColorSwatch.lerp(swatchA, swatchB, 0.0), + const ColorSwatch(0x00000000, {1: Color(0x00000000)}), + ); + expect( + ColorSwatch.lerp(swatchA, swatchB, 0.5), + const ColorSwatch(0x7F7F7F7F, {1: Color(0x7F7F7F7F)}), + ); + expect( + ColorSwatch.lerp(swatchA, swatchB, 1.0), + const ColorSwatch(0xFFFFFFFF, {1: Color(0xFFFFFFFF)}), + ); + expect( + ColorSwatch.lerp(swatchA, swatchB, -0.1), + const ColorSwatch(0x00000000, {1: Color(0x00000000)}), + ); + expect( + ColorSwatch.lerp(swatchA, swatchB, 1.1), + const ColorSwatch(0xFFFFFFFF, {1: Color(0xFFFFFFFF)}), + ); + }); + test('ColorDiagnosticsProperty includes valueProperties in JSON', () { ColorProperty property = ColorProperty('foo', const Color.fromARGB(10, 20, 30, 40)); final Map valueProperties = property.toJsonMap(const DiagnosticsSerializationDelegate())['valueProperties']! as Map;